<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Linux on 夜云泊</title>
    <link>https://lifeislife.cn/tags/linux/</link>
    <description>feedId:57980998056508425+userId:73222296380546048 Recent content in Linux on 夜云泊</description>
    <generator>Hugo -- 0.165.0</generator>
    <language>zh</language>
    <lastBuildDate>Fri, 21 Nov 2025 22:00:00 +0800</lastBuildDate>
    <atom:link href="https://lifeislife.cn/tags/linux/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>阿里云轻量服务器配置Swap解决内存不足</title>
      <link>https://lifeislife.cn/posts/%E9%98%BF%E9%87%8C%E4%BA%91%E8%BD%BB%E9%87%8F%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%85%8D%E7%BD%AEswap%E8%A7%A3%E5%86%B3%E5%86%85%E5%AD%98%E4%B8%8D%E8%B6%B3/</link>
      <pubDate>Fri, 21 Nov 2025 22:00:00 +0800</pubDate>
      <guid>https://lifeislife.cn/posts/%E9%98%BF%E9%87%8C%E4%BA%91%E8%BD%BB%E9%87%8F%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%85%8D%E7%BD%AEswap%E8%A7%A3%E5%86%B3%E5%86%85%E5%AD%98%E4%B8%8D%E8%B6%B3/</guid>
      <description>&lt;h2 id=&#34;问题背景&#34;&gt;问题背景&lt;/h2&gt;
&lt;p&gt;在使用阿里云轻量服务器时，经常会遇到一个令人头疼的问题：&lt;strong&gt;默认配置没有 Swap 交换空间&lt;/strong&gt;。当运行内存占用较高的应用（如编译项目、运行 CI/CD 流程、部署应用等）时，服务器经常会因为内存不足而卡死或无响应。&lt;/p&gt;
&lt;p&gt;我在每次执行 Deploy 部署操作时都会遇到这个问题，机器直接卡死，无法继续工作。通过配置 Swap 交换空间，成功缓解了这一问题，现在运行稳定多了。&lt;/p&gt;
&lt;h2 id=&#34;什么是-swap&#34;&gt;什么是 Swap？&lt;/h2&gt;
&lt;p&gt;Swap（交换空间）是 Linux 系统中的一种虚拟内存技术。当物理内存（RAM）不足时，系统会将暂时不用的数据从内存转移到硬盘上的 Swap 空间，从而释放内存供其他程序使用。虽然 Swap 的读写速度比物理内存慢，但它可以有效防止系统因内存不足而崩溃。&lt;/p&gt;
&lt;h2 id=&#34;配置步骤&#34;&gt;配置步骤&lt;/h2&gt;
&lt;h3 id=&#34;1-检查当前-swap-状态&#34;&gt;1. 检查当前 Swap 状态&lt;/h3&gt;
&lt;p&gt;首先，我们需要确认系统当前是否已经配置了 Swap：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;free -h
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;swapon --show
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果 &lt;code&gt;Swap&lt;/code&gt; 行显示为 0，说明系统没有配置交换空间。&lt;/p&gt;
&lt;h3 id=&#34;2-创建-swap-文件&#34;&gt;2. 创建 Swap 文件&lt;/h3&gt;
&lt;p&gt;根据服务器内存大小，建议创建与内存容量相等或稍大的 Swap 空间。以 2GB 内存的服务器为例，创建 2GB 的 Swap 文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 方法一：使用 fallocate 快速创建（推荐）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo fallocate -l 2G /swapfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 方法二：如果 fallocate 命令不可用，使用 dd 命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo dd &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&#34;nv&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/swapfile &lt;span class=&#34;nv&#34;&gt;bs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1G &lt;span class=&#34;nv&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;说明&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/swapfile&lt;/code&gt; 是 Swap 文件的路径，可以根据需要修改&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2G&lt;/code&gt; 表示创建 2GB 大小的文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fallocate&lt;/code&gt; 命令速度更快，优先使用&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;3-设置文件权限&#34;&gt;3. 设置文件权限&lt;/h3&gt;
&lt;p&gt;为了安全，Swap 文件应该只允许 root 用户读写：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo chmod &lt;span class=&#34;m&#34;&gt;600&lt;/span&gt; /swapfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;4-格式化为-swap-格式&#34;&gt;4. 格式化为 Swap 格式&lt;/h3&gt;
&lt;p&gt;将创建的文件格式化为 Swap 交换空间：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo mkswap /swapfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;5-启用-swap&#34;&gt;5. 启用 Swap&lt;/h3&gt;
&lt;p&gt;激活刚刚创建的 Swap 文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo swapon /swapfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;6-验证-swap-是否生效&#34;&gt;6. 验证 Swap 是否生效&lt;/h3&gt;
&lt;p&gt;再次查看内存和 Swap 状态：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;free -h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              total        used        free      shared  buff/cache   available
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Mem:           2.0G        1.2G        100M         10M        700M        600M
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Swap:          2.0G          0B        2.0G
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到 Swap 一行已经显示 2.0G，说明配置成功。&lt;/p&gt;
&lt;h3 id=&#34;7-配置开机自动挂载&#34;&gt;7. 配置开机自动挂载&lt;/h3&gt;
&lt;p&gt;为了让 Swap 在系统重启后自动生效，需要将其写入 &lt;code&gt;/etc/fstab&lt;/code&gt; 文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;/swapfile none swap sw 0 0&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee -a /etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;验证 &lt;code&gt;/etc/fstab&lt;/code&gt; 配置是否正确：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;优化建议&#34;&gt;优化建议&lt;/h2&gt;
&lt;h3 id=&#34;调整-swappiness-参数可选&#34;&gt;调整 Swappiness 参数（可选）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;swappiness&lt;/code&gt; 参数控制系统使用 Swap 的积极程度，取值范围 0-100：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;0&lt;/strong&gt;：尽可能不使用 Swap，只在内存完全不足时使用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;60&lt;/strong&gt;（默认值）：平衡使用物理内存和 Swap&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;100&lt;/strong&gt;：积极使用 Swap&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于内存较小的服务器，建议将 &lt;code&gt;swappiness&lt;/code&gt; 设置为 10-30，避免过度使用 Swap 导致性能下降：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 查看当前 swappiness 值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /proc/sys/vm/swappiness
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 临时修改（重启后失效）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo sysctl vm.swappiness&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 永久修改&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;vm.swappiness=10&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee -a /etc/sysctl.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo sysctl -p
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;注意事项&#34;&gt;注意事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;硬盘空间占用&lt;/strong&gt;：Swap 文件会占用硬盘空间，创建前请确保有足够的磁盘空间&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能影响&lt;/strong&gt;：虽然 Swap 可以缓解内存不足问题，但过度使用会导致系统变慢，因为硬盘读写速度远低于内存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;监控使用情况&lt;/strong&gt;：建议定期监控 Swap 的使用情况，如果经常大量使用 Swap，说明需要升级服务器配置或优化应用&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;监控-swap-使用情况&#34;&gt;监控 Swap 使用情况&lt;/h2&gt;
&lt;h3 id=&#34;实时查看内存和-swap-状态&#34;&gt;实时查看内存和 Swap 状态&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 查看内存使用情况&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;free -h
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 持续监控（每 2 秒刷新一次）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;watch -n &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; free -h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;查看哪些进程在使用-swap&#34;&gt;查看哪些进程在使用 Swap&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; file in /proc/*/status &lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; awk &lt;span class=&#34;s1&#34;&gt;&amp;#39;/VmSwap|Name/{printf $2 &amp;#34; &amp;#34; $3}END{ print &amp;#34;&amp;#34;}&amp;#39;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sort -k &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; -n -r &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; head -10
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;删除-swap如需移除&#34;&gt;删除 Swap（如需移除）&lt;/h2&gt;
&lt;p&gt;如果以后需要删除 Swap 配置，可以执行以下步骤：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 1. 关闭 Swap&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo swapoff /swapfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 2. 从 /etc/fstab 中删除对应行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo sed -i &lt;span class=&#34;s1&#34;&gt;&amp;#39;/\/swapfile/d&amp;#39;&lt;/span&gt; /etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 3. 删除 Swap 文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo rm /swapfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;配置 Swap 是解决小内存服务器运行大型应用的有效方案。虽然不能完全替代物理内存，但可以在一定程度上缓解内存不足导致的系统卡死问题。对于阿里云轻量服务器这类默认没有 Swap 的环境，强烈建议配置 Swap 以提高系统稳定性。&lt;/p&gt;
&lt;p&gt;当然，如果应用长期大量使用 Swap，最根本的解决方案还是&lt;strong&gt;升级服务器配置或优化应用程序的内存使用&lt;/strong&gt;。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="问题背景">问题背景</h2>
<p>在使用阿里云轻量服务器时，经常会遇到一个令人头疼的问题：<strong>默认配置没有 Swap 交换空间</strong>。当运行内存占用较高的应用（如编译项目、运行 CI/CD 流程、部署应用等）时，服务器经常会因为内存不足而卡死或无响应。</p>
<p>我在每次执行 Deploy 部署操作时都会遇到这个问题，机器直接卡死，无法继续工作。通过配置 Swap 交换空间，成功缓解了这一问题，现在运行稳定多了。</p>
<h2 id="什么是-swap">什么是 Swap？</h2>
<p>Swap（交换空间）是 Linux 系统中的一种虚拟内存技术。当物理内存（RAM）不足时，系统会将暂时不用的数据从内存转移到硬盘上的 Swap 空间，从而释放内存供其他程序使用。虽然 Swap 的读写速度比物理内存慢，但它可以有效防止系统因内存不足而崩溃。</p>
<h2 id="配置步骤">配置步骤</h2>
<h3 id="1-检查当前-swap-状态">1. 检查当前 Swap 状态</h3>
<p>首先，我们需要确认系统当前是否已经配置了 Swap：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">free -h
</span></span><span class="line"><span class="cl">swapon --show
</span></span></code></pre></div><p>如果 <code>Swap</code> 行显示为 0，说明系统没有配置交换空间。</p>
<h3 id="2-创建-swap-文件">2. 创建 Swap 文件</h3>
<p>根据服务器内存大小，建议创建与内存容量相等或稍大的 Swap 空间。以 2GB 内存的服务器为例，创建 2GB 的 Swap 文件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 方法一：使用 fallocate 快速创建（推荐）</span>
</span></span><span class="line"><span class="cl">sudo fallocate -l 2G /swapfile
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 方法二：如果 fallocate 命令不可用，使用 dd 命令</span>
</span></span><span class="line"><span class="cl">sudo dd <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span>/swapfile <span class="nv">bs</span><span class="o">=</span>1G <span class="nv">count</span><span class="o">=</span><span class="m">2</span>
</span></span></code></pre></div><p><strong>说明</strong>：</p>
<ul>
<li><code>/swapfile</code> 是 Swap 文件的路径，可以根据需要修改</li>
<li><code>2G</code> 表示创建 2GB 大小的文件</li>
<li><code>fallocate</code> 命令速度更快，优先使用</li>
</ul>
<h3 id="3-设置文件权限">3. 设置文件权限</h3>
<p>为了安全，Swap 文件应该只允许 root 用户读写：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo chmod <span class="m">600</span> /swapfile
</span></span></code></pre></div><h3 id="4-格式化为-swap-格式">4. 格式化为 Swap 格式</h3>
<p>将创建的文件格式化为 Swap 交换空间：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo mkswap /swapfile
</span></span></code></pre></div><h3 id="5-启用-swap">5. 启用 Swap</h3>
<p>激活刚刚创建的 Swap 文件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo swapon /swapfile
</span></span></code></pre></div><h3 id="6-验证-swap-是否生效">6. 验证 Swap 是否生效</h3>
<p>再次查看内存和 Swap 状态：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">free -h
</span></span></code></pre></div><p>输出示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">              total        used        free      shared  buff/cache   available
</span></span><span class="line"><span class="cl">Mem:           2.0G        1.2G        100M         10M        700M        600M
</span></span><span class="line"><span class="cl">Swap:          2.0G          0B        2.0G
</span></span></code></pre></div><p>可以看到 Swap 一行已经显示 2.0G，说明配置成功。</p>
<h3 id="7-配置开机自动挂载">7. 配置开机自动挂载</h3>
<p>为了让 Swap 在系统重启后自动生效，需要将其写入 <code>/etc/fstab</code> 文件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;/swapfile none swap sw 0 0&#39;</span> <span class="p">|</span> sudo tee -a /etc/fstab
</span></span></code></pre></div><p>验证 <code>/etc/fstab</code> 配置是否正确：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cat /etc/fstab
</span></span></code></pre></div><h2 id="优化建议">优化建议</h2>
<h3 id="调整-swappiness-参数可选">调整 Swappiness 参数（可选）</h3>
<p><code>swappiness</code> 参数控制系统使用 Swap 的积极程度，取值范围 0-100：</p>
<ul>
<li><strong>0</strong>：尽可能不使用 Swap，只在内存完全不足时使用</li>
<li><strong>60</strong>（默认值）：平衡使用物理内存和 Swap</li>
<li><strong>100</strong>：积极使用 Swap</li>
</ul>
<p>对于内存较小的服务器，建议将 <code>swappiness</code> 设置为 10-30，避免过度使用 Swap 导致性能下降：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看当前 swappiness 值</span>
</span></span><span class="line"><span class="cl">cat /proc/sys/vm/swappiness
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 临时修改（重启后失效）</span>
</span></span><span class="line"><span class="cl">sudo sysctl vm.swappiness<span class="o">=</span><span class="m">10</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 永久修改</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;vm.swappiness=10&#39;</span> <span class="p">|</span> sudo tee -a /etc/sysctl.conf
</span></span><span class="line"><span class="cl">sudo sysctl -p
</span></span></code></pre></div><h2 id="注意事项">注意事项</h2>
<ol>
<li><strong>硬盘空间占用</strong>：Swap 文件会占用硬盘空间，创建前请确保有足够的磁盘空间</li>
<li><strong>性能影响</strong>：虽然 Swap 可以缓解内存不足问题，但过度使用会导致系统变慢，因为硬盘读写速度远低于内存</li>
<li><strong>监控使用情况</strong>：建议定期监控 Swap 的使用情况，如果经常大量使用 Swap，说明需要升级服务器配置或优化应用</li>
</ol>
<h2 id="监控-swap-使用情况">监控 Swap 使用情况</h2>
<h3 id="实时查看内存和-swap-状态">实时查看内存和 Swap 状态</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看内存使用情况</span>
</span></span><span class="line"><span class="cl">free -h
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 持续监控（每 2 秒刷新一次）</span>
</span></span><span class="line"><span class="cl">watch -n <span class="m">2</span> free -h
</span></span></code></pre></div><h3 id="查看哪些进程在使用-swap">查看哪些进程在使用 Swap</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="k">for</span> file in /proc/*/status <span class="p">;</span> <span class="k">do</span> awk <span class="s1">&#39;/VmSwap|Name/{printf $2 &#34; &#34; $3}END{ print &#34;&#34;}&#39;</span> <span class="nv">$file</span><span class="p">;</span> <span class="k">done</span> <span class="p">|</span> sort -k <span class="m">2</span> -n -r <span class="p">|</span> head -10
</span></span></code></pre></div><h2 id="删除-swap如需移除">删除 Swap（如需移除）</h2>
<p>如果以后需要删除 Swap 配置，可以执行以下步骤：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. 关闭 Swap</span>
</span></span><span class="line"><span class="cl">sudo swapoff /swapfile
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. 从 /etc/fstab 中删除对应行</span>
</span></span><span class="line"><span class="cl">sudo sed -i <span class="s1">&#39;/\/swapfile/d&#39;</span> /etc/fstab
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. 删除 Swap 文件</span>
</span></span><span class="line"><span class="cl">sudo rm /swapfile
</span></span></code></pre></div><h2 id="总结">总结</h2>
<p>配置 Swap 是解决小内存服务器运行大型应用的有效方案。虽然不能完全替代物理内存，但可以在一定程度上缓解内存不足导致的系统卡死问题。对于阿里云轻量服务器这类默认没有 Swap 的环境，强烈建议配置 Swap 以提高系统稳定性。</p>
<p>当然，如果应用长期大量使用 Swap，最根本的解决方案还是<strong>升级服务器配置或优化应用程序的内存使用</strong>。</p>
]]></content:encoded>
    </item>
    <item>
      <title>VSCode SFTP插件实现本地代码与远程服务器同步</title>
      <link>https://lifeislife.cn/posts/vscode-sftp%E6%8F%92%E4%BB%B6%E5%AE%9E%E7%8E%B0%E6%9C%AC%E5%9C%B0%E4%BB%A3%E7%A0%81%E4%B8%8E%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%90%8C%E6%AD%A5/</link>
      <pubDate>Fri, 21 Nov 2025 10:03:10 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/vscode-sftp%E6%8F%92%E4%BB%B6%E5%AE%9E%E7%8E%B0%E6%9C%AC%E5%9C%B0%E4%BB%A3%E7%A0%81%E4%B8%8E%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%90%8C%E6%AD%A5/</guid>
      <description>&lt;p&gt;在日常开发中，我们经常需要在本地编写代码，然后将代码同步到远程服务器进行测试或部署。传统的方式是使用 FileZilla、WinSCP 等第三方工具手动上传文件，这种方式不仅繁琐，而且容易出错。VSCode 的 SFTP 插件可以帮助我们实现本地代码与远程服务器的自动同步，大大提高开发效率。&lt;/p&gt;
&lt;h2 id=&#34;应用场景&#34;&gt;应用场景&lt;/h2&gt;
&lt;p&gt;SFTP 插件适用于以下场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本地开发，远程调试&lt;/strong&gt;：在本地编写代码，保存后自动同步到远程服务器，无需手动上传&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快速部署&lt;/strong&gt;：本地测试通过后，一键同步到生产环境服务器&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多服务器管理&lt;/strong&gt;：同时管理多个远程服务器，快速切换上传目标&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;团队协作&lt;/strong&gt;：统一开发环境，确保代码在服务器端运行一致&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;安装插件&#34;&gt;安装插件&lt;/h2&gt;
&lt;p&gt;打开 VSCode，按下快捷键 &lt;code&gt;Ctrl + Shift + X&lt;/code&gt; 打开扩展商店，搜索 &lt;code&gt;sftp&lt;/code&gt;，找到名为 &lt;strong&gt;SFTP&lt;/strong&gt; 的插件（作者：Natizyskunk），这是安装量最高、最受欢迎的 SFTP 插件。点击安装即可。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104114810.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104114810.png&#34; alt=&#34;SFTP插件&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;安装完成后，VSCode 会在侧边栏显示 SFTP 图标，表示插件已成功安装。&lt;/p&gt;
&lt;h2 id=&#34;配置插件&#34;&gt;配置插件&lt;/h2&gt;
&lt;h3 id=&#34;生成配置文件&#34;&gt;生成配置文件&lt;/h3&gt;
&lt;p&gt;插件安装完成后，我们需要为当前项目创建配置文件。有两种方式：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方式一：使用命令面板&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;按下快捷键 &lt;code&gt;Ctrl + Shift + P&lt;/code&gt; 打开命令面板&lt;/li&gt;
&lt;li&gt;输入 &lt;code&gt;SFTP: Config&lt;/code&gt; 并回车&lt;/li&gt;
&lt;li&gt;VSCode 会在当前工作区的 &lt;code&gt;.vscode&lt;/code&gt; 文件夹下自动生成 &lt;code&gt;sftp.json&lt;/code&gt; 配置文件&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;方式二：右键菜单&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在 VSCode 资源管理器中，右键点击项目文件夹&lt;/li&gt;
&lt;li&gt;选择 &lt;code&gt;SFTP: Config&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;同样会生成 &lt;code&gt;sftp.json&lt;/code&gt; 配置文件&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;基础配置示例&#34;&gt;基础配置示例&lt;/h3&gt;
&lt;p&gt;打开生成的 &lt;code&gt;sftp.json&lt;/code&gt; 文件，你会看到一个默认的配置模板。下面是一个基础配置示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;我的服务器&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.1.100&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;your_password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;remotePath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/www/project&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;useTempFile&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;openSsh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;完整配置示例&#34;&gt;完整配置示例&lt;/h3&gt;
&lt;p&gt;下面是一个包含更多选项的完整配置示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;生产环境服务器&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.1.100&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;deployer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;your_password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;remotePath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/deployer/project&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;context&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;./&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;useTempFile&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;openSsh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;downloadOnOpen&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;.vscode&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;.git&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;.DS_Store&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;node_modules&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.log&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.tmp&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;watcher&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;files&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;autoUpload&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;autoDelete&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;syncOption&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;delete&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;skipCreate&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignoreExisting&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;update&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;sshConfigPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;concurrency&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;配置参数详解&#34;&gt;配置参数详解&lt;/h2&gt;
&lt;h3 id=&#34;连接配置参数&#34;&gt;连接配置参数&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
					&lt;th&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;配置名称，用于区分多个服务器配置&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;生产环境&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;host&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;服务器 IP 地址或域名（必填）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;192.168.1.100&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;port&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Number&lt;/td&gt;
					&lt;td&gt;端口号，SFTP 默认 22，FTP 默认 21&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;22&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;protocol&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;传输协议，可选 &lt;code&gt;sftp&lt;/code&gt; 或 &lt;code&gt;ftp&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;sftp&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;username&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;登录用户名（必填）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;root&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;password&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;登录密码&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;your_password&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;认证方式参数&#34;&gt;认证方式参数&lt;/h3&gt;
&lt;p&gt;SFTP 插件支持三种认证方式：&lt;/p&gt;
&lt;h4 id=&#34;1-密码认证最简单&#34;&gt;1. 密码认证（最简单）&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;your_password&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;2-密钥认证推荐&#34;&gt;2. 密钥认证（推荐）&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;privateKeyPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;C:\\Users\\YourName\\.ssh\\id_rsa&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;passphrase&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;密钥密码（如果有的话）&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;密钥文件路径说明：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows: &lt;code&gt;C:\\Users\\YourName\\.ssh\\id_rsa&lt;/code&gt; 或 &lt;code&gt;~/.ssh/id_rsa&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Linux/Mac: &lt;code&gt;~/.ssh/id_rsa&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;支持 OpenSSH 格式和 PPK 格式的密钥&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;3-ssh-config-配置高级&#34;&gt;3. SSH Config 配置（高级）&lt;/h4&gt;
&lt;p&gt;如果你已经配置了 SSH config 文件，可以直接引用：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;sshConfigPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;~/.ssh/config&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;myserver&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对应的 SSH config 文件内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Host myserver
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    HostName 192.168.1.100
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    User deployer
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Port 22
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    IdentityFile ~/.ssh/id_rsa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;路径配置参数&#34;&gt;路径配置参数&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
					&lt;th&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;remotePath&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;远程服务器的目标路径（必填）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;/var/www/project&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;context&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;本地项目的相对路径，默认为 &lt;code&gt;./&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;&amp;quot;./src&amp;quot;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;路径配置说明：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;假设本地项目结构如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;project/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── src/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── index.js
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── utils.js
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── tests/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── .vscode/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    └── sftp.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;如果 &lt;code&gt;context&lt;/code&gt; 为 &lt;code&gt;&amp;quot;./&amp;quot;&lt;/code&gt; 且 &lt;code&gt;remotePath&lt;/code&gt; 为 &lt;code&gt;&amp;quot;/var/www/project&amp;quot;&lt;/code&gt;，则 &lt;code&gt;src/index.js&lt;/code&gt; 会上传到 &lt;code&gt;/var/www/project/src/index.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;context&lt;/code&gt; 为 &lt;code&gt;&amp;quot;./src&amp;quot;&lt;/code&gt; 且 &lt;code&gt;remotePath&lt;/code&gt; 为 &lt;code&gt;&amp;quot;/var/www/project&amp;quot;&lt;/code&gt;，则 &lt;code&gt;src/index.js&lt;/code&gt; 会上传到 &lt;code&gt;/var/www/project/index.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;自动同步参数&#34;&gt;自动同步参数&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
					&lt;th&gt;默认值&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;uploadOnSave&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;保存文件时自动上传&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;downloadOnOpen&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;打开文件时自动下载最新版本&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;useTempFile&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;上传时使用临时文件（避免覆盖）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;最佳实践建议：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发环境：设置 &lt;code&gt;uploadOnSave: true&lt;/code&gt;，方便快速同步&lt;/li&gt;
&lt;li&gt;生产环境：设置 &lt;code&gt;uploadOnSave: false&lt;/code&gt;，避免误操作&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;忽略文件配置&#34;&gt;忽略文件配置&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ignore&lt;/code&gt; 参数用于指定哪些文件或文件夹不需要同步，支持 glob 模式：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/.vscode/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/.git/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/.DS_Store&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/node_modules/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/*.log&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/*.tmp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/dist/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/coverage/**&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;常用忽略模式：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;**/.git/**&lt;/code&gt;：忽略 Git 版本控制文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;**/node_modules/**&lt;/code&gt;：忽略 Node.js 依赖包&lt;/li&gt;
&lt;li&gt;&lt;code&gt;**/*.log&lt;/code&gt;：忽略所有日志文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;**/dist/**&lt;/code&gt;：忽略构建输出目录&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;监听器配置watcher&#34;&gt;监听器配置（Watcher）&lt;/h3&gt;
&lt;p&gt;监听器可以监控文件变化并自动执行同步操作：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;watcher&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;files&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;autoUpload&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;autoDelete&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
					&lt;th&gt;默认值&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;files&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;String&lt;/td&gt;
					&lt;td&gt;监听的文件模式（glob）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;autoUpload&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;文件变化时自动上传&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;autoDelete&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;本地删除文件时自动删除远程文件&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;注意事项：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;autoDelete: true&lt;/code&gt; 可能导致误删除，请谨慎使用&lt;/li&gt;
&lt;li&gt;监听器会持续运行，可能影响性能，建议按需启用&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;同步选项sync-option&#34;&gt;同步选项（Sync Option）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;syncOption&lt;/code&gt; 用于配置手动同步时的行为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;syncOption&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;delete&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;skipCreate&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignoreExisting&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;update&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;delete&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;删除远程服务器上多余的文件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;skipCreate&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;跳过创建新文件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;ignoreExisting&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;忽略已存在的文件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;update&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Boolean&lt;/td&gt;
					&lt;td&gt;更新已修改的文件&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;性能优化参数&#34;&gt;性能优化参数&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;参数&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
					&lt;th&gt;默认值&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;concurrency&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Number&lt;/td&gt;
					&lt;td&gt;并发上传的文件数量&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;connectTimeout&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Number&lt;/td&gt;
					&lt;td&gt;连接超时时间（毫秒）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;10000&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;keepalive&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Number&lt;/td&gt;
					&lt;td&gt;保持连接的间隔时间（毫秒）&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;10000&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;concurrency&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;connectTimeout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;15000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;keepalive&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;性能优化建议：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网络环境好时，可以增加 &lt;code&gt;concurrency&lt;/code&gt; 提高上传速度&lt;/li&gt;
&lt;li&gt;网络不稳定时，增加 &lt;code&gt;connectTimeout&lt;/code&gt; 避免连接超时&lt;/li&gt;
&lt;li&gt;频繁操作时，减小 &lt;code&gt;keepalive&lt;/code&gt; 保持连接活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;插件使用&#34;&gt;插件使用&lt;/h2&gt;
&lt;h3 id=&#34;常用操作&#34;&gt;常用操作&lt;/h3&gt;
&lt;p&gt;安装并配置好插件后，可以通过以下方式使用：&lt;/p&gt;
&lt;h4 id=&#34;1-上传文件或文件夹&#34;&gt;1. 上传文件或文件夹&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;方式一：右键菜单&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在资源管理器中右键点击文件或文件夹&lt;/li&gt;
&lt;li&gt;选择 &lt;code&gt;Upload&lt;/code&gt; 上传到服务器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;方式二：命令面板&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;按 &lt;code&gt;Ctrl + Shift + P&lt;/code&gt; 打开命令面板&lt;/li&gt;
&lt;li&gt;输入 &lt;code&gt;SFTP: Upload&lt;/code&gt; 并选择相应的命令&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;2-下载文件或文件夹&#34;&gt;2. 下载文件或文件夹&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;右键点击文件或文件夹&lt;/li&gt;
&lt;li&gt;选择 &lt;code&gt;Download&lt;/code&gt; 从服务器下载&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;3-同步操作&#34;&gt;3. 同步操作&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;同步本地到远程：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;命令面板输入 &lt;code&gt;SFTP: Sync Local -&amp;gt; Remote&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;将本地所有文件同步到服务器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;同步远程到本地：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;命令面板输入 &lt;code&gt;SFTP: Sync Remote -&amp;gt; Local&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;将服务器文件同步到本地&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;双向同步：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;命令面板输入 &lt;code&gt;SFTP: Sync Both Directions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;根据文件修改时间自动判断同步方向&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;4-对比文件差异&#34;&gt;4. 对比文件差异&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;右键点击文件&lt;/li&gt;
&lt;li&gt;选择 &lt;code&gt;Diff with Remote&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;VSCode 会显示本地文件和远程文件的差异&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;5-列出远程文件&#34;&gt;5. 列出远程文件&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;命令面板输入 &lt;code&gt;SFTP: List&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;可以浏览远程服务器的文件目录&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;完整命令列表&#34;&gt;完整命令列表&lt;/h3&gt;
&lt;p&gt;按 &lt;code&gt;Ctrl + Shift + P&lt;/code&gt; 打开命令面板，输入 &lt;code&gt;SFTP&lt;/code&gt; 可以看到所有可用命令：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;命令&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Config&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;创建或编辑配置文件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Upload&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;上传当前文件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Upload Folder&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;上传整个文件夹&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Download&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;下载当前文件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Download Folder&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;下载整个文件夹&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Sync Local -&amp;gt; Remote&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;本地同步到远程&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Sync Remote -&amp;gt; Local&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;远程同步到本地&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Sync Both Directions&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;双向同步&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Diff with Remote&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;对比本地和远程文件&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: List&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;列出远程目录&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: List All&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;列出所有配置的服务器&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;SFTP: Delete&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;删除远程文件&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;多服务器配置&#34;&gt;多服务器配置&lt;/h2&gt;
&lt;p&gt;在实际开发中，我们可能需要同时管理开发环境、测试环境和生产环境多个服务器。SFTP 插件支持在一个配置文件中配置多个服务器。&lt;/p&gt;
&lt;h3 id=&#34;配置多个服务器&#34;&gt;配置多个服务器&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;sftp.json&lt;/code&gt; 中使用数组格式配置多个服务器：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;开发环境&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.1.101&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;developer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;dev_password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;remotePath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/developer/project&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;.vscode/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;.git/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;node_modules/**&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;测试环境&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.1.102&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;tester&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test_password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;remotePath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/www/test&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;.vscode/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;.git/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;node_modules/**&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;生产环境&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.1.103&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;deployer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;privateKeyPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;~/.ssh/production_key&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;remotePath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/var/www/production&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;.vscode/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;.git/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;node_modules/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;切换服务器&#34;&gt;切换服务器&lt;/h3&gt;
&lt;p&gt;配置多个服务器后，每次执行上传、下载等操作时，VSCode 会弹出选择框，让你选择目标服务器。&lt;/p&gt;
&lt;p&gt;也可以通过命令面板 &lt;code&gt;SFTP: List All&lt;/code&gt; 查看所有配置的服务器。&lt;/p&gt;
&lt;h2 id=&#34;最佳实践&#34;&gt;最佳实践&lt;/h2&gt;
&lt;h3 id=&#34;1-安全配置建议&#34;&gt;1. 安全配置建议&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;不要将密码明文写入配置文件：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;方案一：使用环境变量&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${env.SFTP_USER}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${env.SFTP_PASSWORD}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;方案二：使用密钥认证（推荐）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;deployer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;privateKeyPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;~/.ssh/id_rsa&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;将配置文件加入 .gitignore：&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.vscode/sftp.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果需要团队共享配置，可以创建一个 &lt;code&gt;sftp.json.example&lt;/code&gt; 模板文件，将敏感信息替换为占位符：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;示例配置&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;your_server_ip&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;your_username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;your_password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;remotePath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/path/to/project&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;2-工作流建议&#34;&gt;2. 工作流建议&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;开发阶段：&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;downloadOnOpen&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;watcher&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;autoUpload&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;部署阶段：&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;syncOption&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;update&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;delete&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;3-团队协作建议&#34;&gt;3. 团队协作建议&lt;/h3&gt;
&lt;p&gt;为团队创建统一的配置模板：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;团队开发服务器&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${env.DEV_SERVER}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${env.DEV_USER}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${env.DEV_PASSWORD}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;remotePath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/${env.DEV_USER}/project&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;.vscode/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;.git/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;.env&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;node_modules/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;*.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;团队成员在本地创建 &lt;code&gt;.env&lt;/code&gt; 文件配置自己的环境变量即可。&lt;/p&gt;
&lt;h3 id=&#34;4-性能优化建议&#34;&gt;4. 性能优化建议&lt;/h3&gt;
&lt;p&gt;对于大型项目，建议优化以下配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;concurrency&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;node_modules/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;dist/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;build/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;.git/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/*.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;syncOption&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;update&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;常见问题&#34;&gt;常见问题&lt;/h2&gt;
&lt;h3 id=&#34;1-连接超时&#34;&gt;1. 连接超时&lt;/h3&gt;
&lt;p&gt;**问题：**上传文件时提示连接超时。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查服务器 IP 和端口是否正确&lt;/li&gt;
&lt;li&gt;检查防火墙是否开放对应端口&lt;/li&gt;
&lt;li&gt;增加 &lt;code&gt;connectTimeout&lt;/code&gt; 参数：
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;connectTimeout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;30000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;2-权限不足&#34;&gt;2. 权限不足&lt;/h3&gt;
&lt;p&gt;**问题：**上传文件提示 &lt;code&gt;Permission denied&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确认登录用户对目标目录有写权限&lt;/li&gt;
&lt;li&gt;在服务器上执行：&lt;code&gt;chmod 755 /target/path&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;或切换到有权限的用户&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;3-密钥认证失败&#34;&gt;3. 密钥认证失败&lt;/h3&gt;
&lt;p&gt;**问题：**使用密钥登录时提示认证失败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确认密钥文件路径正确&lt;/li&gt;
&lt;li&gt;确认密钥文件权限：&lt;code&gt;chmod 600 ~/.ssh/id_rsa&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;如果密钥有密码，需要配置 &lt;code&gt;passphrase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Windows 用户注意路径格式：&lt;code&gt;C:\\Users\\Name\\.ssh\\id_rsa&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;4-文件同步冲突&#34;&gt;4. 文件同步冲突&lt;/h3&gt;
&lt;p&gt;**问题：**本地和远程文件都被修改，不知道以哪个为准。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;Diff with Remote&lt;/code&gt; 对比差异&lt;/li&gt;
&lt;li&gt;手动合并代码后再上传&lt;/li&gt;
&lt;li&gt;使用版本控制工具如 Git 管理代码&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;5-上传速度慢&#34;&gt;5. 上传速度慢&lt;/h3&gt;
&lt;p&gt;**问题：**上传大量文件时速度很慢。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增加并发数：&lt;code&gt;&amp;quot;concurrency&amp;quot;: 10&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;完善 &lt;code&gt;ignore&lt;/code&gt; 配置，避免上传不必要的文件&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;Sync Local -&amp;gt; Remote&lt;/code&gt; 而不是 &lt;code&gt;Upload Folder&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/liximomo/vscode-sftp&#34;&gt;SFTP 插件官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ssh.com/academy/ssh/keygen&#34;&gt;SSH 密钥认证配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02&#34;&gt;SFTP 协议介绍&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<p>在日常开发中，我们经常需要在本地编写代码，然后将代码同步到远程服务器进行测试或部署。传统的方式是使用 FileZilla、WinSCP 等第三方工具手动上传文件，这种方式不仅繁琐，而且容易出错。VSCode 的 SFTP 插件可以帮助我们实现本地代码与远程服务器的自动同步，大大提高开发效率。</p>
<h2 id="应用场景">应用场景</h2>
<p>SFTP 插件适用于以下场景：</p>
<ul>
<li><strong>本地开发，远程调试</strong>：在本地编写代码，保存后自动同步到远程服务器，无需手动上传</li>
<li><strong>快速部署</strong>：本地测试通过后，一键同步到生产环境服务器</li>
<li><strong>多服务器管理</strong>：同时管理多个远程服务器，快速切换上传目标</li>
<li><strong>团队协作</strong>：统一开发环境，确保代码在服务器端运行一致</li>
</ul>
<h2 id="安装插件">安装插件</h2>
<p>打开 VSCode，按下快捷键 <code>Ctrl + Shift + X</code> 打开扩展商店，搜索 <code>sftp</code>，找到名为 <strong>SFTP</strong> 的插件（作者：Natizyskunk），这是安装量最高、最受欢迎的 SFTP 插件。点击安装即可。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104114810.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104114810.png" alt="SFTP插件"  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>安装完成后，VSCode 会在侧边栏显示 SFTP 图标，表示插件已成功安装。</p>
<h2 id="配置插件">配置插件</h2>
<h3 id="生成配置文件">生成配置文件</h3>
<p>插件安装完成后，我们需要为当前项目创建配置文件。有两种方式：</p>
<p><strong>方式一：使用命令面板</strong></p>
<ol>
<li>按下快捷键 <code>Ctrl + Shift + P</code> 打开命令面板</li>
<li>输入 <code>SFTP: Config</code> 并回车</li>
<li>VSCode 会在当前工作区的 <code>.vscode</code> 文件夹下自动生成 <code>sftp.json</code> 配置文件</li>
</ol>
<p><strong>方式二：右键菜单</strong></p>
<ol>
<li>在 VSCode 资源管理器中，右键点击项目文件夹</li>
<li>选择 <code>SFTP: Config</code></li>
<li>同样会生成 <code>sftp.json</code> 配置文件</li>
</ol>
<h3 id="基础配置示例">基础配置示例</h3>
<p>打开生成的 <code>sftp.json</code> 文件，你会看到一个默认的配置模板。下面是一个基础配置示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;我的服务器&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.1.100&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;sftp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;root&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;your_password&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;remotePath&#34;</span><span class="p">:</span> <span class="s2">&#34;/var/www/project&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;useTempFile&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;openSsh&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="完整配置示例">完整配置示例</h3>
<p>下面是一个包含更多选项的完整配置示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;生产环境服务器&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.1.100&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;sftp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;deployer&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;your_password&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;remotePath&#34;</span><span class="p">:</span> <span class="s2">&#34;/home/deployer/project&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;context&#34;</span><span class="p">:</span> <span class="s2">&#34;./&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;useTempFile&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;openSsh&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;downloadOnOpen&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;.vscode&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;.git&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;.DS_Store&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;node_modules&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;*.log&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;*.tmp&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;watcher&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;files&#34;</span><span class="p">:</span> <span class="s2">&#34;**/*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;autoUpload&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;autoDelete&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;syncOption&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;delete&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;skipCreate&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;ignoreExisting&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;update&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;sshConfigPath&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;concurrency&#34;</span><span class="p">:</span> <span class="mi">4</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="配置参数详解">配置参数详解</h2>
<h3 id="连接配置参数">连接配置参数</h3>
<table>
	<thead>
			<tr>
					<th>参数</th>
					<th>类型</th>
					<th>说明</th>
					<th>示例</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>name</code></td>
					<td>String</td>
					<td>配置名称，用于区分多个服务器配置</td>
					<td><code>&quot;生产环境&quot;</code></td>
			</tr>
			<tr>
					<td><code>host</code></td>
					<td>String</td>
					<td>服务器 IP 地址或域名（必填）</td>
					<td><code>&quot;192.168.1.100&quot;</code></td>
			</tr>
			<tr>
					<td><code>port</code></td>
					<td>Number</td>
					<td>端口号，SFTP 默认 22，FTP 默认 21</td>
					<td><code>22</code></td>
			</tr>
			<tr>
					<td><code>protocol</code></td>
					<td>String</td>
					<td>传输协议，可选 <code>sftp</code> 或 <code>ftp</code></td>
					<td><code>&quot;sftp&quot;</code></td>
			</tr>
			<tr>
					<td><code>username</code></td>
					<td>String</td>
					<td>登录用户名（必填）</td>
					<td><code>&quot;root&quot;</code></td>
			</tr>
			<tr>
					<td><code>password</code></td>
					<td>String</td>
					<td>登录密码</td>
					<td><code>&quot;your_password&quot;</code></td>
			</tr>
	</tbody>
</table>
<h3 id="认证方式参数">认证方式参数</h3>
<p>SFTP 插件支持三种认证方式：</p>
<h4 id="1-密码认证最简单">1. 密码认证（最简单）</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;root&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;your_password&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h4 id="2-密钥认证推荐">2. 密钥认证（推荐）</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;root&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;privateKeyPath&#34;</span><span class="p">:</span> <span class="s2">&#34;C:\\Users\\YourName\\.ssh\\id_rsa&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;passphrase&#34;</span><span class="p">:</span> <span class="s2">&#34;密钥密码（如果有的话）&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>密钥文件路径说明：</strong></p>
<ul>
<li>Windows: <code>C:\\Users\\YourName\\.ssh\\id_rsa</code> 或 <code>~/.ssh/id_rsa</code></li>
<li>Linux/Mac: <code>~/.ssh/id_rsa</code></li>
<li>支持 OpenSSH 格式和 PPK 格式的密钥</li>
</ul>
<h4 id="3-ssh-config-配置高级">3. SSH Config 配置（高级）</h4>
<p>如果你已经配置了 SSH config 文件，可以直接引用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;sshConfigPath&#34;</span><span class="p">:</span> <span class="s2">&#34;~/.ssh/config&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;myserver&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>对应的 SSH config 文件内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Host myserver
</span></span><span class="line"><span class="cl">    HostName 192.168.1.100
</span></span><span class="line"><span class="cl">    User deployer
</span></span><span class="line"><span class="cl">    Port 22
</span></span><span class="line"><span class="cl">    IdentityFile ~/.ssh/id_rsa
</span></span></code></pre></div><h3 id="路径配置参数">路径配置参数</h3>
<table>
	<thead>
			<tr>
					<th>参数</th>
					<th>类型</th>
					<th>说明</th>
					<th>示例</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>remotePath</code></td>
					<td>String</td>
					<td>远程服务器的目标路径（必填）</td>
					<td><code>&quot;/var/www/project&quot;</code></td>
			</tr>
			<tr>
					<td><code>context</code></td>
					<td>String</td>
					<td>本地项目的相对路径，默认为 <code>./</code></td>
					<td><code>&quot;./src&quot;</code></td>
			</tr>
	</tbody>
</table>
<p><strong>路径配置说明：</strong></p>
<p>假设本地项目结构如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">project/
</span></span><span class="line"><span class="cl">├── src/
</span></span><span class="line"><span class="cl">│   ├── index.js
</span></span><span class="line"><span class="cl">│   └── utils.js
</span></span><span class="line"><span class="cl">├── tests/
</span></span><span class="line"><span class="cl">└── .vscode/
</span></span><span class="line"><span class="cl">    └── sftp.json
</span></span></code></pre></div><ul>
<li>如果 <code>context</code> 为 <code>&quot;./&quot;</code> 且 <code>remotePath</code> 为 <code>&quot;/var/www/project&quot;</code>，则 <code>src/index.js</code> 会上传到 <code>/var/www/project/src/index.js</code></li>
<li>如果 <code>context</code> 为 <code>&quot;./src&quot;</code> 且 <code>remotePath</code> 为 <code>&quot;/var/www/project&quot;</code>，则 <code>src/index.js</code> 会上传到 <code>/var/www/project/index.js</code></li>
</ul>
<h3 id="自动同步参数">自动同步参数</h3>
<table>
	<thead>
			<tr>
					<th>参数</th>
					<th>类型</th>
					<th>说明</th>
					<th>默认值</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>uploadOnSave</code></td>
					<td>Boolean</td>
					<td>保存文件时自动上传</td>
					<td><code>false</code></td>
			</tr>
			<tr>
					<td><code>downloadOnOpen</code></td>
					<td>Boolean</td>
					<td>打开文件时自动下载最新版本</td>
					<td><code>false</code></td>
			</tr>
			<tr>
					<td><code>useTempFile</code></td>
					<td>Boolean</td>
					<td>上传时使用临时文件（避免覆盖）</td>
					<td><code>false</code></td>
			</tr>
	</tbody>
</table>
<p><strong>最佳实践建议：</strong></p>
<ul>
<li>开发环境：设置 <code>uploadOnSave: true</code>，方便快速同步</li>
<li>生产环境：设置 <code>uploadOnSave: false</code>，避免误操作</li>
</ul>
<h3 id="忽略文件配置">忽略文件配置</h3>
<p><code>ignore</code> 参数用于指定哪些文件或文件夹不需要同步，支持 glob 模式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/.vscode/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/.git/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/.DS_Store&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/node_modules/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/*.log&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/*.tmp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/dist/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/coverage/**&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>常用忽略模式：</strong></p>
<ul>
<li><code>**/.git/**</code>：忽略 Git 版本控制文件</li>
<li><code>**/node_modules/**</code>：忽略 Node.js 依赖包</li>
<li><code>**/*.log</code>：忽略所有日志文件</li>
<li><code>**/dist/**</code>：忽略构建输出目录</li>
</ul>
<h3 id="监听器配置watcher">监听器配置（Watcher）</h3>
<p>监听器可以监控文件变化并自动执行同步操作：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;watcher&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;files&#34;</span><span class="p">:</span> <span class="s2">&#34;**/*&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;autoUpload&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;autoDelete&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><table>
	<thead>
			<tr>
					<th>参数</th>
					<th>类型</th>
					<th>说明</th>
					<th>默认值</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>files</code></td>
					<td>String</td>
					<td>监听的文件模式（glob）</td>
					<td><code>false</code></td>
			</tr>
			<tr>
					<td><code>autoUpload</code></td>
					<td>Boolean</td>
					<td>文件变化时自动上传</td>
					<td><code>false</code></td>
			</tr>
			<tr>
					<td><code>autoDelete</code></td>
					<td>Boolean</td>
					<td>本地删除文件时自动删除远程文件</td>
					<td><code>false</code></td>
			</tr>
	</tbody>
</table>
<p><strong>注意事项：</strong></p>
<ul>
<li><code>autoDelete: true</code> 可能导致误删除，请谨慎使用</li>
<li>监听器会持续运行，可能影响性能，建议按需启用</li>
</ul>
<h3 id="同步选项sync-option">同步选项（Sync Option）</h3>
<p><code>syncOption</code> 用于配置手动同步时的行为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;syncOption&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;delete&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;skipCreate&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;ignoreExisting&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;update&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><table>
	<thead>
			<tr>
					<th>参数</th>
					<th>类型</th>
					<th>说明</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>delete</code></td>
					<td>Boolean</td>
					<td>删除远程服务器上多余的文件</td>
			</tr>
			<tr>
					<td><code>skipCreate</code></td>
					<td>Boolean</td>
					<td>跳过创建新文件</td>
			</tr>
			<tr>
					<td><code>ignoreExisting</code></td>
					<td>Boolean</td>
					<td>忽略已存在的文件</td>
			</tr>
			<tr>
					<td><code>update</code></td>
					<td>Boolean</td>
					<td>更新已修改的文件</td>
			</tr>
	</tbody>
</table>
<h3 id="性能优化参数">性能优化参数</h3>
<table>
	<thead>
			<tr>
					<th>参数</th>
					<th>类型</th>
					<th>说明</th>
					<th>默认值</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>concurrency</code></td>
					<td>Number</td>
					<td>并发上传的文件数量</td>
					<td><code>4</code></td>
			</tr>
			<tr>
					<td><code>connectTimeout</code></td>
					<td>Number</td>
					<td>连接超时时间（毫秒）</td>
					<td><code>10000</code></td>
			</tr>
			<tr>
					<td><code>keepalive</code></td>
					<td>Number</td>
					<td>保持连接的间隔时间（毫秒）</td>
					<td><code>10000</code></td>
			</tr>
	</tbody>
</table>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;concurrency&#34;</span><span class="p">:</span> <span class="mi">8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;connectTimeout&#34;</span><span class="p">:</span> <span class="mi">15000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;keepalive&#34;</span><span class="p">:</span> <span class="mi">5000</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>性能优化建议：</strong></p>
<ul>
<li>网络环境好时，可以增加 <code>concurrency</code> 提高上传速度</li>
<li>网络不稳定时，增加 <code>connectTimeout</code> 避免连接超时</li>
<li>频繁操作时，减小 <code>keepalive</code> 保持连接活跃</li>
</ul>
<h2 id="插件使用">插件使用</h2>
<h3 id="常用操作">常用操作</h3>
<p>安装并配置好插件后，可以通过以下方式使用：</p>
<h4 id="1-上传文件或文件夹">1. 上传文件或文件夹</h4>
<p><strong>方式一：右键菜单</strong></p>
<ul>
<li>在资源管理器中右键点击文件或文件夹</li>
<li>选择 <code>Upload</code> 上传到服务器</li>
</ul>
<p><strong>方式二：命令面板</strong></p>
<ul>
<li>按 <code>Ctrl + Shift + P</code> 打开命令面板</li>
<li>输入 <code>SFTP: Upload</code> 并选择相应的命令</li>
</ul>
<h4 id="2-下载文件或文件夹">2. 下载文件或文件夹</h4>
<ul>
<li>右键点击文件或文件夹</li>
<li>选择 <code>Download</code> 从服务器下载</li>
</ul>
<h4 id="3-同步操作">3. 同步操作</h4>
<p><strong>同步本地到远程：</strong></p>
<ul>
<li>命令面板输入 <code>SFTP: Sync Local -&gt; Remote</code></li>
<li>将本地所有文件同步到服务器</li>
</ul>
<p><strong>同步远程到本地：</strong></p>
<ul>
<li>命令面板输入 <code>SFTP: Sync Remote -&gt; Local</code></li>
<li>将服务器文件同步到本地</li>
</ul>
<p><strong>双向同步：</strong></p>
<ul>
<li>命令面板输入 <code>SFTP: Sync Both Directions</code></li>
<li>根据文件修改时间自动判断同步方向</li>
</ul>
<h4 id="4-对比文件差异">4. 对比文件差异</h4>
<ul>
<li>右键点击文件</li>
<li>选择 <code>Diff with Remote</code></li>
<li>VSCode 会显示本地文件和远程文件的差异</li>
</ul>
<h4 id="5-列出远程文件">5. 列出远程文件</h4>
<ul>
<li>命令面板输入 <code>SFTP: List</code></li>
<li>可以浏览远程服务器的文件目录</li>
</ul>
<h3 id="完整命令列表">完整命令列表</h3>
<p>按 <code>Ctrl + Shift + P</code> 打开命令面板，输入 <code>SFTP</code> 可以看到所有可用命令：</p>
<table>
	<thead>
			<tr>
					<th>命令</th>
					<th>说明</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>SFTP: Config</code></td>
					<td>创建或编辑配置文件</td>
			</tr>
			<tr>
					<td><code>SFTP: Upload</code></td>
					<td>上传当前文件</td>
			</tr>
			<tr>
					<td><code>SFTP: Upload Folder</code></td>
					<td>上传整个文件夹</td>
			</tr>
			<tr>
					<td><code>SFTP: Download</code></td>
					<td>下载当前文件</td>
			</tr>
			<tr>
					<td><code>SFTP: Download Folder</code></td>
					<td>下载整个文件夹</td>
			</tr>
			<tr>
					<td><code>SFTP: Sync Local -&gt; Remote</code></td>
					<td>本地同步到远程</td>
			</tr>
			<tr>
					<td><code>SFTP: Sync Remote -&gt; Local</code></td>
					<td>远程同步到本地</td>
			</tr>
			<tr>
					<td><code>SFTP: Sync Both Directions</code></td>
					<td>双向同步</td>
			</tr>
			<tr>
					<td><code>SFTP: Diff with Remote</code></td>
					<td>对比本地和远程文件</td>
			</tr>
			<tr>
					<td><code>SFTP: List</code></td>
					<td>列出远程目录</td>
			</tr>
			<tr>
					<td><code>SFTP: List All</code></td>
					<td>列出所有配置的服务器</td>
			</tr>
			<tr>
					<td><code>SFTP: Delete</code></td>
					<td>删除远程文件</td>
			</tr>
	</tbody>
</table>
<h2 id="多服务器配置">多服务器配置</h2>
<p>在实际开发中，我们可能需要同时管理开发环境、测试环境和生产环境多个服务器。SFTP 插件支持在一个配置文件中配置多个服务器。</p>
<h3 id="配置多个服务器">配置多个服务器</h3>
<p>在 <code>sftp.json</code> 中使用数组格式配置多个服务器：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;开发环境&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.1.101&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;developer&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;dev_password&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;sftp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;remotePath&#34;</span><span class="p">:</span> <span class="s2">&#34;/home/developer/project&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;.vscode/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;.git/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;node_modules/**&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;测试环境&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.1.102&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;tester&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;test_password&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;sftp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;remotePath&#34;</span><span class="p">:</span> <span class="s2">&#34;/var/www/test&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;.vscode/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;.git/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;node_modules/**&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;生产环境&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.1.103&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;deployer&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;privateKeyPath&#34;</span><span class="p">:</span> <span class="s2">&#34;~/.ssh/production_key&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;sftp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;remotePath&#34;</span><span class="p">:</span> <span class="s2">&#34;/var/www/production&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;.vscode/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;.git/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;node_modules/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;*.log&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></div><h3 id="切换服务器">切换服务器</h3>
<p>配置多个服务器后，每次执行上传、下载等操作时，VSCode 会弹出选择框，让你选择目标服务器。</p>
<p>也可以通过命令面板 <code>SFTP: List All</code> 查看所有配置的服务器。</p>
<h2 id="最佳实践">最佳实践</h2>
<h3 id="1-安全配置建议">1. 安全配置建议</h3>
<p><strong>不要将密码明文写入配置文件：</strong></p>
<p>方案一：使用环境变量</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;${env.SFTP_USER}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;${env.SFTP_PASSWORD}&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>方案二：使用密钥认证（推荐）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;deployer&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;privateKeyPath&#34;</span><span class="p">:</span> <span class="s2">&#34;~/.ssh/id_rsa&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>将配置文件加入 .gitignore：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">.vscode/sftp.json
</span></span></code></pre></div><p>如果需要团队共享配置，可以创建一个 <code>sftp.json.example</code> 模板文件，将敏感信息替换为占位符：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;示例配置&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;your_server_ip&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;your_username&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;your_password&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;remotePath&#34;</span><span class="p">:</span> <span class="s2">&#34;/path/to/project&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="2-工作流建议">2. 工作流建议</h3>
<p><strong>开发阶段：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;downloadOnOpen&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;watcher&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;autoUpload&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>部署阶段：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;syncOption&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;update&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;delete&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="3-团队协作建议">3. 团队协作建议</h3>
<p>为团队创建统一的配置模板：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;团队开发服务器&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;${env.DEV_SERVER}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;${env.DEV_USER}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;${env.DEV_PASSWORD}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;remotePath&#34;</span><span class="p">:</span> <span class="s2">&#34;/home/${env.DEV_USER}/project&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;.vscode/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;.git/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;.env&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;node_modules/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;*.log&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>团队成员在本地创建 <code>.env</code> 文件配置自己的环境变量即可。</p>
<h3 id="4-性能优化建议">4. 性能优化建议</h3>
<p>对于大型项目，建议优化以下配置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;concurrency&#34;</span><span class="p">:</span> <span class="mi">8</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;node_modules/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;dist/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;build/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;.git/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;**/*.log&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;syncOption&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;update&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="常见问题">常见问题</h2>
<h3 id="1-连接超时">1. 连接超时</h3>
<p>**问题：**上传文件时提示连接超时。</p>
<p><strong>解决方案：</strong></p>
<ul>
<li>检查服务器 IP 和端口是否正确</li>
<li>检查防火墙是否开放对应端口</li>
<li>增加 <code>connectTimeout</code> 参数：
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;connectTimeout&#34;</span><span class="p">:</span> <span class="mi">30000</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ul>
<h3 id="2-权限不足">2. 权限不足</h3>
<p>**问题：**上传文件提示 <code>Permission denied</code>。</p>
<p><strong>解决方案：</strong></p>
<ul>
<li>确认登录用户对目标目录有写权限</li>
<li>在服务器上执行：<code>chmod 755 /target/path</code></li>
<li>或切换到有权限的用户</li>
</ul>
<h3 id="3-密钥认证失败">3. 密钥认证失败</h3>
<p>**问题：**使用密钥登录时提示认证失败。</p>
<p><strong>解决方案：</strong></p>
<ul>
<li>确认密钥文件路径正确</li>
<li>确认密钥文件权限：<code>chmod 600 ~/.ssh/id_rsa</code></li>
<li>如果密钥有密码，需要配置 <code>passphrase</code></li>
<li>Windows 用户注意路径格式：<code>C:\\Users\\Name\\.ssh\\id_rsa</code></li>
</ul>
<h3 id="4-文件同步冲突">4. 文件同步冲突</h3>
<p>**问题：**本地和远程文件都被修改，不知道以哪个为准。</p>
<p><strong>解决方案：</strong></p>
<ul>
<li>使用 <code>Diff with Remote</code> 对比差异</li>
<li>手动合并代码后再上传</li>
<li>使用版本控制工具如 Git 管理代码</li>
</ul>
<h3 id="5-上传速度慢">5. 上传速度慢</h3>
<p>**问题：**上传大量文件时速度很慢。</p>
<p><strong>解决方案：</strong></p>
<ul>
<li>增加并发数：<code>&quot;concurrency&quot;: 10</code></li>
<li>完善 <code>ignore</code> 配置，避免上传不必要的文件</li>
<li>使用 <code>Sync Local -&gt; Remote</code> 而不是 <code>Upload Folder</code></li>
</ul>
<h2 id="参考资料">参考资料</h2>
<ul>
<li><a href="https://github.com/liximomo/vscode-sftp">SFTP 插件官方文档</a></li>
<li><a href="https://www.ssh.com/academy/ssh/keygen">SSH 密钥认证配置</a></li>
<li><a href="https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02">SFTP 协议介绍</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 清理磁盘释放空间</title>
      <link>https://lifeislife.cn/posts/linux-%E6%B8%85%E7%90%86%E7%A3%81%E7%9B%98%E9%87%8A%E6%94%BE%E7%A9%BA%E9%97%B4/</link>
      <pubDate>Sat, 21 Sep 2024 10:10:20 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux-%E6%B8%85%E7%90%86%E7%A3%81%E7%9B%98%E9%87%8A%E6%94%BE%E7%A9%BA%E9%97%B4/</guid>
      <description>&lt;p&gt;NAS 的系统磁盘空间告急了，当初用了一张就笔记本闲置的固态硬盘，只有 128G，心想光做系统盘应该足够了，结果还是经不住折腾，需要清理一下磁盘空间。本文记录了一些常用的清理磁盘空间的方法。&lt;/p&gt;
&lt;h2 id=&#34;查看磁盘使用情况&#34;&gt;查看磁盘使用情况&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;df -h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;清理软件包&#34;&gt;清理软件包&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理旧版本缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get autoclean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理所有缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 移除孤立软件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get autoremove
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;清理日志&#34;&gt;清理日志&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 查看 journal 日志占用的硬盘空间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;journalctl -x --disk-usage
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理日志到只剩下 10M&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;journalctl --vacuum-size&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10M
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理一天前的日志&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;journalctl --vacuum-time&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 永久限制 journal 日志的大小：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;Journal&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SystemMaxUse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10M   &lt;span class=&#34;c1&#34;&gt;# 硬盘中只保留最近 10M 的日志&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;RuntimeMaxUse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10M  &lt;span class=&#34;c1&#34;&gt;# 内存中只保留最近 10M 的日志&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;清理-docker&#34;&gt;清理 Docker&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理所有停止的容器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker container prune
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理所有未使用的镜像&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker image prune
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理所有未使用的卷&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker volume prune
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理所有未使用的网络&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker network prune
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理所有未使用的镜像、容器、网络、卷，如果你使用docker的话，这一步会释放大量的空间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;docker system prune --volumes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WARNING! This will remove:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - all stopped containers
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - all networks not used by at least one container
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - all volumes not used by at least one container
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - all dangling images
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - all dangling build cache
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;清理-pip-缓存&#34;&gt;清理 pip 缓存&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理 pip 缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip cache purge
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -r ~/.cache/pip
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;大文件查找清理&#34;&gt;大文件查找清理&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 查找大于 100M 的文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find / -type f -size +100M
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 删除大于 100M 的文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find / -type f -size +100M -delete
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>NAS 的系统磁盘空间告急了，当初用了一张就笔记本闲置的固态硬盘，只有 128G，心想光做系统盘应该足够了，结果还是经不住折腾，需要清理一下磁盘空间。本文记录了一些常用的清理磁盘空间的方法。</p>
<h2 id="查看磁盘使用情况">查看磁盘使用情况</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">df -h
</span></span></code></pre></div><h2 id="清理软件包">清理软件包</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 清理旧版本缓存</span>
</span></span><span class="line"><span class="cl">apt-get autoclean
</span></span><span class="line"><span class="cl"><span class="c1"># 清理所有缓存</span>
</span></span><span class="line"><span class="cl">apt-get clean
</span></span><span class="line"><span class="cl"><span class="c1"># 移除孤立软件</span>
</span></span><span class="line"><span class="cl">apt-get autoremove
</span></span></code></pre></div><h2 id="清理日志">清理日志</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看 journal 日志占用的硬盘空间</span>
</span></span><span class="line"><span class="cl">journalctl -x --disk-usage
</span></span><span class="line"><span class="cl"><span class="c1"># 清理日志到只剩下 10M</span>
</span></span><span class="line"><span class="cl">journalctl --vacuum-size<span class="o">=</span>10M
</span></span><span class="line"><span class="cl"><span class="c1"># 清理一天前的日志</span>
</span></span><span class="line"><span class="cl">journalctl --vacuum-time<span class="o">=</span>1d
</span></span><span class="line"><span class="cl"><span class="c1"># 永久限制 journal 日志的大小：</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>Journal<span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="nv">SystemMaxUse</span><span class="o">=</span>10M   <span class="c1"># 硬盘中只保留最近 10M 的日志</span>
</span></span><span class="line"><span class="cl"><span class="nv">RuntimeMaxUse</span><span class="o">=</span>10M  <span class="c1"># 内存中只保留最近 10M 的日志</span>
</span></span></code></pre></div><h2 id="清理-docker">清理 Docker</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 清理所有停止的容器</span>
</span></span><span class="line"><span class="cl">docker container prune
</span></span><span class="line"><span class="cl"><span class="c1"># 清理所有未使用的镜像</span>
</span></span><span class="line"><span class="cl">docker image prune
</span></span><span class="line"><span class="cl"><span class="c1"># 清理所有未使用的卷</span>
</span></span><span class="line"><span class="cl">docker volume prune
</span></span><span class="line"><span class="cl"><span class="c1"># 清理所有未使用的网络</span>
</span></span><span class="line"><span class="cl">docker network prune
</span></span><span class="line"><span class="cl"><span class="c1"># 清理所有未使用的镜像、容器、网络、卷，如果你使用docker的话，这一步会释放大量的空间</span>
</span></span><span class="line"><span class="cl">docker system prune --volumes
</span></span><span class="line"><span class="cl">WARNING! This will remove:
</span></span><span class="line"><span class="cl">  - all stopped containers
</span></span><span class="line"><span class="cl">  - all networks not used by at least one container
</span></span><span class="line"><span class="cl">  - all volumes not used by at least one container
</span></span><span class="line"><span class="cl">  - all dangling images
</span></span><span class="line"><span class="cl">  - all dangling build cache
</span></span></code></pre></div><h2 id="清理-pip-缓存">清理 pip 缓存</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 清理 pip 缓存</span>
</span></span><span class="line"><span class="cl">pip cache purge
</span></span><span class="line"><span class="cl">rm -r ~/.cache/pip
</span></span></code></pre></div><h2 id="大文件查找清理">大文件查找清理</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查找大于 100M 的文件</span>
</span></span><span class="line"><span class="cl">find / -type f -size +100M
</span></span><span class="line"><span class="cl"><span class="c1"># 删除大于 100M 的文件</span>
</span></span><span class="line"><span class="cl">find / -type f -size +100M -delete
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>解决systemd-journald查看日志出现Missed  kernel messages</title>
      <link>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3missed--kernel-messages/</link>
      <pubDate>Sun, 15 Sep 2024 10:10:20 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3missed--kernel-messages/</guid>
      <description>&lt;p&gt;在使用 &lt;code&gt;systemd-journald&lt;/code&gt; 进行日志管理时，遇到内核日志输出过快导致日志丢失的情况时，一般是由于 &lt;code&gt;journald&lt;/code&gt; 的缓冲区设置过小，无法处理快速输出的内核消息。本文将介绍问题原因，并给出相应的解决方案。&lt;/p&gt;
&lt;h2 id=&#34;问题描述&#34;&gt;问题描述&lt;/h2&gt;
&lt;p&gt;当内核日志输出过快时，&lt;code&gt;systemd-journald&lt;/code&gt; 可能会因其内部缓冲区设置过小而无法处理所有日志，导致部分日志信息丢失。表现为系统日志中出现类似以下的错误：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Missed xxx kernel messages
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种情况通常出现在内核大量输出调试信息、系统初始化阶段日志频繁输出，或系统发生较大故障时。&lt;/p&gt;
&lt;h2 id=&#34;原因分析&#34;&gt;原因分析&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;systemd-journald&lt;/code&gt; 是一个处理系统日志的服务，包括内核日志。它通过监听 &lt;code&gt;/dev/kmsg&lt;/code&gt; 获取内核日志信息。journald 使用一个内部缓冲区来暂存日志，如果日志流速过快而 &lt;code&gt;journald&lt;/code&gt; 无法及时处理，这个缓冲区会被填满，导致消息溢出或丢失。&lt;/p&gt;
&lt;p&gt;默认情况下，&lt;code&gt;journald&lt;/code&gt; 的日志缓冲区大小较小，可能无法应对高频率的日志输出。此外，&lt;code&gt;journald&lt;/code&gt; 还可能受限于某些系统资源的配置，如最大消息大小、日志文件大小等。&lt;/p&gt;
&lt;h2 id=&#34;解决方案&#34;&gt;解决方案&lt;/h2&gt;
&lt;p&gt;我们可以通过以下几个步骤来缓解或解决内核日志丢失问题：&lt;/p&gt;
&lt;h3 id=&#34;1-增加-systemd-journald-缓存大小&#34;&gt;1. 增加 &lt;code&gt;systemd-journald&lt;/code&gt; 缓存大小&lt;/h3&gt;
&lt;p&gt;通过调整 &lt;code&gt;systemd-journald&lt;/code&gt; 的配置来增大其缓冲区，可以减少日志丢失的情况。&lt;/p&gt;
&lt;p&gt;编辑 &lt;code&gt;journald&lt;/code&gt; 的配置文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo vim /etc/systemd/journald.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;找到以下参数并进行调整：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# RuntimeMaxUse: 设置运行时日志文件的最大使用空间。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 可以将此值设为较大的值，例如 100M。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;RuntimeMaxUse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;100M&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# SystemMaxUse: 设置系统日志文件的最大使用空间。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 可以将此值设为 500M。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;SystemMaxUse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;500M&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# RateLimitInterval: 限制日志接收速率的时间间隔。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 可以适当延长此时间，例如 10s。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;RateLimitInterval&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;10s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# RateLimitBurst: 限制日志接收速率的最大突发数。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 增加突发限制，比如 10000。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;RateLimitBurst&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;10000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存并关闭文件，然后重启 &lt;code&gt;journald&lt;/code&gt; 服务使配置生效：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl restart systemd-journald
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;2-调整内核日志环形缓冲区的大小&#34;&gt;2. 调整内核日志环形缓冲区的大小&lt;/h3&gt;
&lt;p&gt;内核日志存储在一个环形缓冲区中，该缓冲区的大小可以通过 &lt;code&gt;dmesg&lt;/code&gt; 命令查看和调整。默认的缓冲区可能较小，可以通过 &lt;code&gt;kernel&lt;/code&gt; 命令行参数 &lt;code&gt;log_buf_len&lt;/code&gt; 来调整。&lt;/p&gt;
&lt;p&gt;编辑 &lt;code&gt;grub&lt;/code&gt; 配置文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo vim /etc/default/grub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt; 行中添加如下参数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;log_buf_len=16M&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这将内核日志缓冲区设置为 16M。保存并更新 grub：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-grub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后重启系统以应用更改：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;3-禁用日志速率限制&#34;&gt;3. 禁用日志速率限制&lt;/h3&gt;
&lt;p&gt;如果日志速率限制不符合当前系统需求，可以考虑禁用速率限制，尤其是在开发和调试环境中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo vim /etc/systemd/journald.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在配置文件中禁用日志速率限制：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;RateLimitInterval&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;RateLimitBurst&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存文件并重启 &lt;code&gt;systemd-journald&lt;/code&gt; 服务：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl restart systemd-journald
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>在使用 <code>systemd-journald</code> 进行日志管理时，遇到内核日志输出过快导致日志丢失的情况时，一般是由于 <code>journald</code> 的缓冲区设置过小，无法处理快速输出的内核消息。本文将介绍问题原因，并给出相应的解决方案。</p>
<h2 id="问题描述">问题描述</h2>
<p>当内核日志输出过快时，<code>systemd-journald</code> 可能会因其内部缓冲区设置过小而无法处理所有日志，导致部分日志信息丢失。表现为系统日志中出现类似以下的错误：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Missed xxx kernel messages
</span></span></code></pre></div><p>这种情况通常出现在内核大量输出调试信息、系统初始化阶段日志频繁输出，或系统发生较大故障时。</p>
<h2 id="原因分析">原因分析</h2>
<p><code>systemd-journald</code> 是一个处理系统日志的服务，包括内核日志。它通过监听 <code>/dev/kmsg</code> 获取内核日志信息。journald 使用一个内部缓冲区来暂存日志，如果日志流速过快而 <code>journald</code> 无法及时处理，这个缓冲区会被填满，导致消息溢出或丢失。</p>
<p>默认情况下，<code>journald</code> 的日志缓冲区大小较小，可能无法应对高频率的日志输出。此外，<code>journald</code> 还可能受限于某些系统资源的配置，如最大消息大小、日志文件大小等。</p>
<h2 id="解决方案">解决方案</h2>
<p>我们可以通过以下几个步骤来缓解或解决内核日志丢失问题：</p>
<h3 id="1-增加-systemd-journald-缓存大小">1. 增加 <code>systemd-journald</code> 缓存大小</h3>
<p>通过调整 <code>systemd-journald</code> 的配置来增大其缓冲区，可以减少日志丢失的情况。</p>
<p>编辑 <code>journald</code> 的配置文件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo vim /etc/systemd/journald.conf
</span></span></code></pre></div><p>找到以下参数并进行调整：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="c1"># RuntimeMaxUse: 设置运行时日志文件的最大使用空间。</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以将此值设为较大的值，例如 100M。</span>
</span></span><span class="line"><span class="cl"><span class="na">RuntimeMaxUse</span><span class="o">=</span><span class="s">100M</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># SystemMaxUse: 设置系统日志文件的最大使用空间。</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以将此值设为 500M。</span>
</span></span><span class="line"><span class="cl"><span class="na">SystemMaxUse</span><span class="o">=</span><span class="s">500M</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># RateLimitInterval: 限制日志接收速率的时间间隔。</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 可以适当延长此时间，例如 10s。</span>
</span></span><span class="line"><span class="cl"><span class="na">RateLimitInterval</span><span class="o">=</span><span class="s">10s</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># RateLimitBurst: 限制日志接收速率的最大突发数。</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 增加突发限制，比如 10000。</span>
</span></span><span class="line"><span class="cl"><span class="na">RateLimitBurst</span><span class="o">=</span><span class="s">10000</span>
</span></span></code></pre></div><p>保存并关闭文件，然后重启 <code>journald</code> 服务使配置生效：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo systemctl restart systemd-journald
</span></span></code></pre></div><h3 id="2-调整内核日志环形缓冲区的大小">2. 调整内核日志环形缓冲区的大小</h3>
<p>内核日志存储在一个环形缓冲区中，该缓冲区的大小可以通过 <code>dmesg</code> 命令查看和调整。默认的缓冲区可能较小，可以通过 <code>kernel</code> 命令行参数 <code>log_buf_len</code> 来调整。</p>
<p>编辑 <code>grub</code> 配置文件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo vim /etc/default/grub
</span></span></code></pre></div><p>在 <code>GRUB_CMDLINE_LINUX_DEFAULT</code> 行中添加如下参数：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">GRUB_CMDLINE_LINUX_DEFAULT</span><span class="o">=</span><span class="s2">&#34;log_buf_len=16M&#34;</span>
</span></span></code></pre></div><p>这将内核日志缓冲区设置为 16M。保存并更新 grub：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo update-grub
</span></span></code></pre></div><p>然后重启系统以应用更改：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo reboot
</span></span></code></pre></div><h3 id="3-禁用日志速率限制">3. 禁用日志速率限制</h3>
<p>如果日志速率限制不符合当前系统需求，可以考虑禁用速率限制，尤其是在开发和调试环境中：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo vim /etc/systemd/journald.conf
</span></span></code></pre></div><p>在配置文件中禁用日志速率限制：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">RateLimitInterval</span><span class="o">=</span><span class="s">0</span>
</span></span><span class="line"><span class="cl"><span class="na">RateLimitBurst</span><span class="o">=</span><span class="s">0</span>
</span></span></code></pre></div><p>保存文件并重启 <code>systemd-journald</code> 服务：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo systemctl restart systemd-journald
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Linux挂载新硬盘</title>
      <link>https://lifeislife.cn/posts/linux%E6%8C%82%E8%BD%BD%E6%96%B0%E7%A1%AC%E7%9B%98/</link>
      <pubDate>Sat, 10 Aug 2024 15:42:13 +0800</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%8C%82%E8%BD%BD%E6%96%B0%E7%A1%AC%E7%9B%98/</guid>
      <description>&lt;p&gt;用qBittorrent下载文件有些资源上传率很低，下载很慢，就会对机械硬盘频繁读写，这样会导致硬盘寿命缩短。虽然组了RAID5，但是还是希望硬盘能活得久一点吧。所以买了一块新固态专门用来下载文件，作为临时存放，等文件下载完了再整块拷贝到RAID5里。OMV本来挂载新硬盘很简单的，UI页面点点就可以了，不知道是不是因为我这块硬盘是通过PCIe转接卡接在主板上的，挂载一直报错。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;OMV&lt;span class=&#34;se&#34;&gt;\E&lt;/span&gt;xecException: Failed to execute &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin; export LANG=C.UTF-8; omv-salt deploy run --no-color fstab 2&amp;gt;&amp;amp;1&amp;#39;&lt;/span&gt; with &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; code &lt;span class=&#34;s1&#34;&gt;&amp;#39;1&amp;#39;&lt;/span&gt;: /usr/lib/python3/dist-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1.26.18&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; or chardet &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;3.0.4&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; doesn&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;t match a supported version!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  RequestsDependencyWarning&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;网上找了一圈也没找到解决办法，只好自己手动挂载了。&lt;/p&gt;
&lt;p&gt;首先查看新硬盘的设备名：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lsblk
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NAME        MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nvme0n1     259:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; 931.5G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; disk  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;fdisk&lt;/code&gt;命令对硬盘进行分区：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fdisk /dev/nvme0n1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Welcome to fdisk &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;util-linux 2.39.1&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Changes will remain in memory only, &lt;span class=&#34;k&#34;&gt;until&lt;/span&gt; you decide to write them.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Be careful before using the write command.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输入n表示新建分区&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Command &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;m &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;help&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Partition &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   p   primary &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; primary, &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; extended, &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; free&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   e   extended &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;container &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; logical partitions&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输入p表示主分区&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Select &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;default p&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: p
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 分区号直接回车使用默认的，新硬盘应该为1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Partition number &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;2-128, default 2&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输入两次回车使用默认的，从第一个扇区开始，到最后一个扇区结束，即整个硬盘&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 我因为已经分区完了，所以找了以前的笔记，所以扇区号和实际的大小，你们只需要两次回车就行了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;First sector &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1001472-452984798, default 1001472&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Last sector, +/-sectors or +/-size&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;K,M,G,T,P&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1001472-452984798, default 452982783&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输入w保存退出&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Command &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;m &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;help&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: w
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The partition table has been altered.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Calling ioctl&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt; to re-read partition table.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Syncing disks.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 分区完成了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;格式化分区：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkfs.ext4 /dev/nvme0n1p1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mke2fs 1.44.5 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;15-Dec-2018&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Creating filesystem with &lt;span class=&#34;m&#34;&gt;244189696&lt;/span&gt; 4k blocks and &lt;span class=&#34;m&#34;&gt;61054976&lt;/span&gt; inodes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Filesystem UUID: 1b1b1b1b-1b1b-1b1b-1b1b-1b1b1b1b1b1b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Superblock backups stored on blocks: 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    102400000, &lt;span class=&#34;m&#34;&gt;214990848&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建挂载点：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 在NAS上创建一个目录，用来挂载新硬盘，我的硬盘都挂载在了srv目录下，所以这里也挂载在srv下&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir /srv/download-disk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;挂载硬盘：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mount /dev/nvme0n1p1 /srv/download-disk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看挂载情况：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ df -h
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Filesystem      Size  Used Avail Use% Mounted on
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;udev            7.6G     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  7.6G   0% /dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs           1.6G   13M  1.5G   1% /run
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda1       116G   97G   14G  88% /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs           7.6G     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  7.6G   0% /dev/shm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs           5.0M     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  5.0M   0% /run/lock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs           7.6G     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  7.6G   0% /sys/fs/cgroup
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/nvme0n1p1  916G   28K  870G   1% /srv/download-disk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为文件系统打上标签，为了能在NAS中能方便区分硬盘，我就用了硬盘的品牌和容量：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;e2label /dev/nvme0n1p1 Kingston1tb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看标签：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ blkid
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设置自动挂载，编辑&lt;code&gt;/etc/fstab&lt;/code&gt;文件，每次重启后都会自动挂载：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/dev/nvme0n1p1 /srv/download-disk ext4 defaults 0 0&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>用qBittorrent下载文件有些资源上传率很低，下载很慢，就会对机械硬盘频繁读写，这样会导致硬盘寿命缩短。虽然组了RAID5，但是还是希望硬盘能活得久一点吧。所以买了一块新固态专门用来下载文件，作为临时存放，等文件下载完了再整块拷贝到RAID5里。OMV本来挂载新硬盘很简单的，UI页面点点就可以了，不知道是不是因为我这块硬盘是通过PCIe转接卡接在主板上的，挂载一直报错。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">OMV<span class="se">\E</span>xecException: Failed to execute <span class="nb">command</span> <span class="s1">&#39;export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin; export LANG=C.UTF-8; omv-salt deploy run --no-color fstab 2&gt;&amp;1&#39;</span> with <span class="nb">exit</span> code <span class="s1">&#39;1&#39;</span>: /usr/lib/python3/dist-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 <span class="o">(</span>1.26.18<span class="o">)</span> or chardet <span class="o">(</span>3.0.4<span class="o">)</span> doesn<span class="err">&#39;</span>t match a supported version!
</span></span><span class="line"><span class="cl">  RequestsDependencyWarning<span class="o">)</span>
</span></span></code></pre></div><p>网上找了一圈也没找到解决办法，只好自己手动挂载了。</p>
<p>首先查看新硬盘的设备名：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">lsblk
</span></span><span class="line"><span class="cl">NAME        MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
</span></span><span class="line"><span class="cl">nvme0n1     259:0    <span class="m">0</span> 931.5G  <span class="m">0</span> disk  
</span></span></code></pre></div><p>使用<code>fdisk</code>命令对硬盘进行分区：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">fdisk /dev/nvme0n1
</span></span><span class="line"><span class="cl">Welcome to fdisk <span class="o">(</span>util-linux 2.39.1<span class="o">)</span>.
</span></span><span class="line"><span class="cl">Changes will remain in memory only, <span class="k">until</span> you decide to write them.
</span></span><span class="line"><span class="cl">Be careful before using the write command.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 输入n表示新建分区</span>
</span></span><span class="line"><span class="cl">Command <span class="o">(</span>m <span class="k">for</span> <span class="nb">help</span><span class="o">)</span>: n
</span></span><span class="line"><span class="cl">Partition <span class="nb">type</span>
</span></span><span class="line"><span class="cl">   p   primary <span class="o">(</span><span class="m">2</span> primary, <span class="m">0</span> extended, <span class="m">2</span> free<span class="o">)</span>
</span></span><span class="line"><span class="cl">   e   extended <span class="o">(</span>container <span class="k">for</span> logical partitions<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 输入p表示主分区</span>
</span></span><span class="line"><span class="cl">Select <span class="o">(</span>default p<span class="o">)</span>: p
</span></span><span class="line"><span class="cl"><span class="c1"># 分区号直接回车使用默认的，新硬盘应该为1</span>
</span></span><span class="line"><span class="cl">Partition number <span class="o">(</span>2-128, default 2<span class="o">)</span>:
</span></span><span class="line"><span class="cl"><span class="c1"># 输入两次回车使用默认的，从第一个扇区开始，到最后一个扇区结束，即整个硬盘</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 我因为已经分区完了，所以找了以前的笔记，所以扇区号和实际的大小，你们只需要两次回车就行了</span>
</span></span><span class="line"><span class="cl">First sector <span class="o">(</span>1001472-452984798, default 1001472<span class="o">)</span>:
</span></span><span class="line"><span class="cl">Last sector, +/-sectors or +/-size<span class="o">{</span>K,M,G,T,P<span class="o">}</span> <span class="o">(</span>1001472-452984798, default 452982783<span class="o">)</span>:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 输入w保存退出</span>
</span></span><span class="line"><span class="cl">Command <span class="o">(</span>m <span class="k">for</span> <span class="nb">help</span><span class="o">)</span>: w
</span></span><span class="line"><span class="cl">The partition table has been altered.
</span></span><span class="line"><span class="cl">Calling ioctl<span class="o">()</span> to re-read partition table.
</span></span><span class="line"><span class="cl">Syncing disks.
</span></span><span class="line"><span class="cl"><span class="c1"># 分区完成了</span>
</span></span></code></pre></div><p>格式化分区：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkfs.ext4 /dev/nvme0n1p1
</span></span><span class="line"><span class="cl">mke2fs 1.44.5 <span class="o">(</span>15-Dec-2018<span class="o">)</span>
</span></span><span class="line"><span class="cl">Creating filesystem with <span class="m">244189696</span> 4k blocks and <span class="m">61054976</span> inodes
</span></span><span class="line"><span class="cl">Filesystem UUID: 1b1b1b1b-1b1b-1b1b-1b1b-1b1b1b1b1b1b
</span></span><span class="line"><span class="cl">Superblock backups stored on blocks: 
</span></span><span class="line"><span class="cl">    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
</span></span><span class="line"><span class="cl">    4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 
</span></span><span class="line"><span class="cl">    102400000, <span class="m">214990848</span>
</span></span></code></pre></div><p>创建挂载点：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 在NAS上创建一个目录，用来挂载新硬盘，我的硬盘都挂载在了srv目录下，所以这里也挂载在srv下</span>
</span></span><span class="line"><span class="cl">mkdir /srv/download-disk
</span></span></code></pre></div><p>挂载硬盘：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mount /dev/nvme0n1p1 /srv/download-disk
</span></span></code></pre></div><p>查看挂载情况：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ df -h
</span></span><span class="line"><span class="cl">Filesystem      Size  Used Avail Use% Mounted on
</span></span><span class="line"><span class="cl">udev            7.6G     <span class="m">0</span>  7.6G   0% /dev
</span></span><span class="line"><span class="cl">tmpfs           1.6G   13M  1.5G   1% /run
</span></span><span class="line"><span class="cl">/dev/sda1       116G   97G   14G  88% /
</span></span><span class="line"><span class="cl">tmpfs           7.6G     <span class="m">0</span>  7.6G   0% /dev/shm
</span></span><span class="line"><span class="cl">tmpfs           5.0M     <span class="m">0</span>  5.0M   0% /run/lock
</span></span><span class="line"><span class="cl">tmpfs           7.6G     <span class="m">0</span>  7.6G   0% /sys/fs/cgroup
</span></span><span class="line"><span class="cl">/dev/nvme0n1p1  916G   28K  870G   1% /srv/download-disk
</span></span></code></pre></div><p>为文件系统打上标签，为了能在NAS中能方便区分硬盘，我就用了硬盘的品牌和容量：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">e2label /dev/nvme0n1p1 Kingston1tb
</span></span></code></pre></div><p>查看标签：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ blkid
</span></span></code></pre></div><p>设置自动挂载，编辑<code>/etc/fstab</code>文件，每次重启后都会自动挂载：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;/dev/nvme0n1p1 /srv/download-disk ext4 defaults 0 0&#34;</span> &gt;&gt; /etc/fstab
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>RemoteX11 远程调试带GUI应用</title>
      <link>https://lifeislife.cn/posts/remotex11-%E8%BF%9C%E7%A8%8B%E8%B0%83%E8%AF%95%E5%B8%A6gui%E5%BA%94%E7%94%A8/</link>
      <pubDate>Sun, 03 Mar 2024 20:45:56 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/remotex11-%E8%BF%9C%E7%A8%8B%E8%B0%83%E8%AF%95%E5%B8%A6gui%E5%BA%94%E7%94%A8/</guid>
      <description>&lt;p&gt;Windows上通过WSL2进行Linux开发，但是有时候需要开发带GUI的引用，这样就需要将图像转发。&lt;/p&gt;
&lt;h2 id=&#34;配置windows&#34;&gt;配置Windows&lt;/h2&gt;
&lt;p&gt;下载安装XMing，启动Xlaunch。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;选择MultiWindow&lt;/li&gt;
&lt;li&gt;设置Display number为10（可以自行设置，主要是需要和后面在WSL2中设置的变量保持一致）&lt;/li&gt;
&lt;li&gt;选择Start no client（Windows的XMing是被动等待接收图像数据，所以选择该项）&lt;/li&gt;
&lt;li&gt;一直下一页，其余保持默认，点击完成即可。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/b1fa974ebfa7e08576cc61bce4307640.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/b1fa974ebfa7e08576cc61bce4307640.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/b0a29ceb2b30d4dc68a9d969859698c3.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/b0a29ceb2b30d4dc68a9d969859698c3.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;配置vscode&#34;&gt;配置VSCode&lt;/h2&gt;
&lt;p&gt;安装RemoteX11插件，直接在插件中心搜索安装即可。&lt;/p&gt;
&lt;p&gt;打开设置页面，搜索Remote x11，找到如下配置项，将Display Number配置为10&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/6bf072325b38892eda270dabf4d3a1be.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/6bf072325b38892eda270dabf4d3a1be.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;配置wsl2&#34;&gt;配置WSL2&lt;/h2&gt;
&lt;p&gt;安装xclock用于测试&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install xclock
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;设置环境变量&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;l&#34;&gt;export DISPLAY=localhost:10.0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 或者&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;l&#34;&gt;export DISPLAY=:0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行xclock查看结果&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/2e35553c8672c1bd92e4320b2d88d562.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/2e35553c8672c1bd92e4320b2d88d562.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>Windows上通过WSL2进行Linux开发，但是有时候需要开发带GUI的引用，这样就需要将图像转发。</p>
<h2 id="配置windows">配置Windows</h2>
<p>下载安装XMing，启动Xlaunch。</p>
<ol>
<li>选择MultiWindow</li>
<li>设置Display number为10（可以自行设置，主要是需要和后面在WSL2中设置的变量保持一致）</li>
<li>选择Start no client（Windows的XMing是被动等待接收图像数据，所以选择该项）</li>
<li>一直下一页，其余保持默认，点击完成即可。</li>
</ol>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/b1fa974ebfa7e08576cc61bce4307640.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/b1fa974ebfa7e08576cc61bce4307640.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/b0a29ceb2b30d4dc68a9d969859698c3.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/b0a29ceb2b30d4dc68a9d969859698c3.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="配置vscode">配置VSCode</h2>
<p>安装RemoteX11插件，直接在插件中心搜索安装即可。</p>
<p>打开设置页面，搜索Remote x11，找到如下配置项，将Display Number配置为10</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/6bf072325b38892eda270dabf4d3a1be.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/6bf072325b38892eda270dabf4d3a1be.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="配置wsl2">配置WSL2</h2>
<p>安装xclock用于测试</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo apt-get install xclock
</span></span></code></pre></div><p>设置环境变量</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yml" data-lang="yml"><span class="line"><span class="cl"><span class="l">export DISPLAY=localhost:10.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c"># 或者</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="l">export DISPLAY=:0</span><span class="w">
</span></span></span></code></pre></div><p>运行xclock查看结果</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/2e35553c8672c1bd92e4320b2d88d562.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/03/03/2e35553c8672c1bd92e4320b2d88d562.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>repo源配置解析</title>
      <link>https://lifeislife.cn/posts/repo%E6%BA%90%E9%85%8D%E7%BD%AE%E8%A7%A3%E6%9E%90/</link>
      <pubDate>Wed, 17 Jan 2024 21:32:04 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/repo%E6%BA%90%E9%85%8D%E7%BD%AE%E8%A7%A3%E6%9E%90/</guid>
      <description>&lt;h1 id=&#34;repo-源配置解析&#34;&gt;repo 源配置解析&lt;/h1&gt;
&lt;p&gt;openEuler 的软件源配置文件位于/etc/yum.repos.d/目录下，以.repo 为后缀名，文件名可以任意取，但是必须以.repo 结尾。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#generic-repos is licensed under the Mulan PSL v2.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#You can use this software according to the terms and conditions of the Mulan PSL v2.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#You may obtain a copy of Mulan PSL v2 at:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#    http://license.coscl.org.cn/MulanPSL2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#THIS SOFTWARE IS PROVIDED ON AN &amp;#34;AS IS&amp;#34; BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#PURPOSE.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#See the Mulan PSL v2 for more details.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[OS]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;name=OS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;baseurl=http://repo.openeuler.org/openEuler-23.09/OS/$basearch/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;metalink=https://mirrors.openeuler.org/metalink?repo=$releasever/OS&amp;amp;arch=$basearch
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;metadata_expire=1h
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;enabled=1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpgcheck=1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpgkey=http://repo.openeuler.org/openEuler-23.09/OS/$basearch/RPM-GPG-KEY-openEuler
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;[source]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;name=source
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;baseurl=http://repo.openeuler.org/openEuler-23.09/source/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;metalink=https://mirrors.openeuler.org/metalink?repo=$releasever&amp;amp;arch=source
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;metadata_expire=1h
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;enabled=1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpgcheck=1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpgkey=http://repo.openeuler.org/openEuler-23.09/source/RPM-GPG-KEY-openEuler
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中各个配置项的含义如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[repoid]中的 repoid 为软件仓库（repository）的 ID 号，所有.repo 配置文件中的各 repoid 不能重复，必须唯一。示例中 repoid 为 OS 和 source。&lt;/li&gt;
&lt;li&gt;name 为软件仓库描述的字符串，可以任意取，但是建议取一个有意义的名称，方便用户理解。示例中 name 为 OS 和 source。&lt;/li&gt;
&lt;li&gt;baseurl 为软件仓库的地址，可以是 http、https、ftp 等协议，也可以是本地目录。&lt;/li&gt;
&lt;li&gt;enabled 为是否启用该软件源仓库，可选值为 1 和 0。默认值为 1，表示启用该软件源仓库。示例中 enabled 为 1。&lt;/li&gt;
&lt;li&gt;metalink 为动态的镜像地址，用于镜像加速。&lt;/li&gt;
&lt;li&gt;metadata_expire 为元数据过期时间，单位为秒。默认值为 90 分钟，即 5400 秒。示例中 metadata_expire 为 1h，即 1 小时。&lt;/li&gt;
&lt;li&gt;gpgcheck 可设置为 1 或 0，1 表示进行 gpg（GNU Private Guard）校验，0 表示不进行 gpg 校验，gpgcheck 可以确定 rpm 包的来源是有效和安全的。&lt;/li&gt;
&lt;li&gt;gpgkey 为验证签名用的公钥地址，如果 gpgcheck 为 1，则必须设置 gpgkey。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;gpgcheck-详解&#34;&gt;gpgcheck 详解&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;RPM-GPG-KEY&lt;/code&gt; 是一个公共密钥，用于验证由该密钥签名的RPM包的真实性和完整性。在使用 &lt;code&gt;yum&lt;/code&gt; 或 &lt;code&gt;dnf&lt;/code&gt; 这样的包管理工具时，这些工具会使用 GPG 密钥来验证软件包的签名，以确保软件包来自于可信的源，且未被篡改。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;命名约定：&lt;/strong&gt; &lt;code&gt;RPM-GPG-KEY&lt;/code&gt; 是一个命名约定，通常与其所属的仓库或发行版相关。例如，如果你在使用某个特定发行版的官方仓库，它可能会提供一个 &lt;code&gt;RPM-GPG-KEY&lt;/code&gt; 文件来进行软件包签名验证。如openEuler官方仓库提供的 &lt;code&gt;RPM-GPG-KEY&lt;/code&gt; 文件名为 &lt;code&gt;RPM-GPG-KEY-openEuler&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;密钥生成：&lt;/strong&gt; 这个密钥是通过 GPG（GNU Privacy Guard）工具生成的。GPG 是一个用于进行加密和签名的开源工具。&lt;code&gt;RPM-GPG-KEY&lt;/code&gt; 文件包含了一个公钥，该公钥由仓库所有者使用私钥签署软件包，而用户使用公钥验证软件包。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;验证软件包：&lt;/strong&gt; 当用户使用 &lt;code&gt;yum&lt;/code&gt; 或 &lt;code&gt;dnf&lt;/code&gt; 安装软件包时，这些工具会检查软件包的签名，并使用相应的 &lt;code&gt;RPM-GPG-KEY&lt;/code&gt; 文件中的公钥来验证签名。如果验证通过，工具会认为软件包是可信的，否则将会发出警告或拒绝安装。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;导入密钥：&lt;/strong&gt; 为了使用 &lt;code&gt;RPM-GPG-KEY&lt;/code&gt; 文件，用户通常需要将密钥导入到本地系统中。这通常可以通过运行类似于以下命令的导入密钥的操作来完成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-openEuler
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述命令中的 &lt;code&gt;/etc/pki/rpm-gpg/RPM-GPG-KEY-openEuler&lt;/code&gt; 路径可能会因发行版和配置而有所不同。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;rpm包签名&#34;&gt;RPM包签名&lt;/h2&gt;
&lt;p&gt;对于发布的 RPM 包进行 GPG 签名是一种重要的安全措施，可以确保接收者能够验证软件包的真实性和完整性。以下是一般的步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;生成 GPG 密钥：&lt;/strong&gt; 如果你还没有 GPG 密钥对，你需要使用 GPG 工具生成一对密钥，包括私钥和公钥。你可以运行以下命令来生成密钥：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpg --gen-key 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当你运行 &lt;code&gt;gpg --gen-key&lt;/code&gt; 命令时，它会启动 GPG（GNU Privacy Guard）的密钥生成过程。这个过程将引导你提供一些必要的信息以生成密钥对，包括私钥和公钥。以下是这个命令的详细步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择密钥类型：&lt;/strong&gt; 你将被要求选择密钥的类型。通常，默认的 RSA 和 DSA 都是可接受的选择，你可以通过键入数字来选择。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择密钥大小：&lt;/strong&gt; 你将被要求选择密钥的大小。通常，默认值（通常是2048位）是足够的，但你也可以选择更大的值。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择密钥的有效期：&lt;/strong&gt; 你将被要求选择密钥的有效期。你可以选择密钥永久有效，或者在一段特定的时间内有效。如果你选择了特定的时间，你需要输入一个表示有效期的值，例如1y表示一年，1m表示一个月。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;提供用户标识信息：&lt;/strong&gt; 你将被要求提供与密钥相关联的用户标识信息。这包括你的真实姓名、电子邮件地址和一个可选的注释。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;确认提供的信息：&lt;/strong&gt; GPG 将显示你提供的信息并询问你是否确认。如果确认无误，你可以输入 &lt;code&gt;O&lt;/code&gt; 或直接按回车键。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;输入保护密语（passphrase）：&lt;/strong&gt; 你将被要求输入保护密语，用于保护你的私钥。请确保选择一个强密码。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;等待密钥生成：&lt;/strong&gt; GPG 将使用提供的信息生成密钥对。这可能需要一些时间，具体取决于你选择的密钥大小。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;生成完成：&lt;/strong&gt; 一旦生成完成，你将看到一条消息表明密钥生成成功。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在整个过程中，你将看到类似以下的一些提示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpg: key ABCDEFGH marked as ultimately trusted
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpg: revocation certificate stored as &lt;span class=&#34;s1&#34;&gt;&amp;#39;/home/your_user/.gnupg/openpgp-revocs.d/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.rev&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;public and secret key created and signed.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpg: checking the trustdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpg: &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; marginal&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; needed, &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; complete&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; needed, PGP trust model
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpg: depth: &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  valid:   &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;  signed:   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  trust: 0-, 0q, 0n, 0m, 0f, 2u
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pub   2048R/XXXXXXXX 2024-01-01 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;expires: 2024-01-01&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Key &lt;span class=&#34;nv&#34;&gt;fingerprint&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; XXXX YYYY ZZZZ AAAA BBBB  CCCC DDDD EEEE FFFF &lt;span class=&#34;m&#34;&gt;1111&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uid                  Your Name &amp;lt;your.email@example.com&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sub   2048R/YYYYYYYY 2024-01-01 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;expires: 2024-01-01&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个例子中，&lt;code&gt;XXXXXXXX&lt;/code&gt; 是你的密钥 ID，&lt;code&gt;YYYYYYYY&lt;/code&gt; 是子密钥的 ID。你可以使用这些 ID 来引用你的密钥。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;导出公钥：&lt;/strong&gt; 生成密钥后，你需要将公钥导出。运行以下命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gpg --output RPM-GPG-KEY-your-repo --armor --export your@email.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这将生成一个 ASCII 格式的公钥文件 &lt;code&gt;RPM-GPG-KEY-your-repo&lt;/code&gt;，你可以与软件包一起发布。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;为 RPM 包签名：&lt;/strong&gt; 在构建 RPM 包时，使用 &lt;code&gt;rpmbuild&lt;/code&gt; 命令时，可以通过添加 &lt;code&gt;--sign&lt;/code&gt; 选项来指示 &lt;code&gt;rpmbuild&lt;/code&gt; 对 RPM 包进行签名。例如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rpmbuild -ba your-package.spec --sign
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当你执行 &lt;code&gt;rpmbuild -ba your-package.spec --sign&lt;/code&gt; 命令时，&lt;code&gt;rpmbuild&lt;/code&gt; 会使用默认的 GPG 密钥进行签名。这通常是你在系统上配置为默认 GPG 密钥的密钥。&lt;/p&gt;
&lt;p&gt;你可以通过检查 &lt;code&gt;rpmbuild&lt;/code&gt; 使用的 GPG 密钥来确认它是哪个密钥：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rpm -q gpg-pubkey --qf &lt;span class=&#34;s1&#34;&gt;&amp;#39;%{name}-%{version}-%{release} --&amp;gt; %{summary}\n&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个命令将显示系统上安装的 GPG 公钥，其中默认的密钥可能是 &amp;ldquo;gpg-pubkey-xxxxxxxx-yyyyyyyy&amp;rdquo;。你可以根据密钥的 &amp;ldquo;xxxxxxxx-yyyyyyyy&amp;rdquo; 部分来确定默认使用的 GPG 密钥。&lt;/p&gt;
&lt;p&gt;如果你想使用不同的 GPG 密钥进行签名，可以在 &lt;code&gt;rpmbuild&lt;/code&gt; 命令中使用 &lt;code&gt;--signwith&lt;/code&gt; 选项，例如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rpmbuild -ba your-package.spec --signwith &amp;lt;key-id&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;&amp;lt;key-id&amp;gt;&lt;/code&gt; 是你想要使用的 GPG 密钥的 ID。这会覆盖默认的密钥。确保你在构建和签名 RPM 包时使用的是正确的 GPG 密钥。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;导入密钥：&lt;/strong&gt; 为了验证你的软件包，用户需要导入你的公钥。他们可以运行以下命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rpm --import RPM-GPG-KEY-your-repo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;发布：&lt;/strong&gt; 将签名的 RPM 包和公钥一起发布。确保用户知道他们可以使用导入的公钥来验证软件包的签名。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</description>
      <content:encoded><![CDATA[<h1 id="repo-源配置解析">repo 源配置解析</h1>
<p>openEuler 的软件源配置文件位于/etc/yum.repos.d/目录下，以.repo 为后缀名，文件名可以任意取，但是必须以.repo 结尾。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">#generic-repos is licensed under the Mulan PSL v2.
</span></span><span class="line"><span class="cl">#You can use this software according to the terms and conditions of the Mulan PSL v2.
</span></span><span class="line"><span class="cl">#You may obtain a copy of Mulan PSL v2 at:
</span></span><span class="line"><span class="cl">#    http://license.coscl.org.cn/MulanPSL2
</span></span><span class="line"><span class="cl">#THIS SOFTWARE IS PROVIDED ON AN &#34;AS IS&#34; BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
</span></span><span class="line"><span class="cl">#IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
</span></span><span class="line"><span class="cl">#PURPOSE.
</span></span><span class="line"><span class="cl">#See the Mulan PSL v2 for more details.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[OS]
</span></span><span class="line"><span class="cl">name=OS
</span></span><span class="line"><span class="cl">baseurl=http://repo.openeuler.org/openEuler-23.09/OS/$basearch/
</span></span><span class="line"><span class="cl">metalink=https://mirrors.openeuler.org/metalink?repo=$releasever/OS&amp;arch=$basearch
</span></span><span class="line"><span class="cl">metadata_expire=1h
</span></span><span class="line"><span class="cl">enabled=1
</span></span><span class="line"><span class="cl">gpgcheck=1
</span></span><span class="line"><span class="cl">gpgkey=http://repo.openeuler.org/openEuler-23.09/OS/$basearch/RPM-GPG-KEY-openEuler
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[source]
</span></span><span class="line"><span class="cl">name=source
</span></span><span class="line"><span class="cl">baseurl=http://repo.openeuler.org/openEuler-23.09/source/
</span></span><span class="line"><span class="cl">metalink=https://mirrors.openeuler.org/metalink?repo=$releasever&amp;arch=source
</span></span><span class="line"><span class="cl">metadata_expire=1h
</span></span><span class="line"><span class="cl">enabled=1
</span></span><span class="line"><span class="cl">gpgcheck=1
</span></span><span class="line"><span class="cl">gpgkey=http://repo.openeuler.org/openEuler-23.09/source/RPM-GPG-KEY-openEuler
</span></span></code></pre></div><p>其中各个配置项的含义如下：</p>
<ul>
<li>[repoid]中的 repoid 为软件仓库（repository）的 ID 号，所有.repo 配置文件中的各 repoid 不能重复，必须唯一。示例中 repoid 为 OS 和 source。</li>
<li>name 为软件仓库描述的字符串，可以任意取，但是建议取一个有意义的名称，方便用户理解。示例中 name 为 OS 和 source。</li>
<li>baseurl 为软件仓库的地址，可以是 http、https、ftp 等协议，也可以是本地目录。</li>
<li>enabled 为是否启用该软件源仓库，可选值为 1 和 0。默认值为 1，表示启用该软件源仓库。示例中 enabled 为 1。</li>
<li>metalink 为动态的镜像地址，用于镜像加速。</li>
<li>metadata_expire 为元数据过期时间，单位为秒。默认值为 90 分钟，即 5400 秒。示例中 metadata_expire 为 1h，即 1 小时。</li>
<li>gpgcheck 可设置为 1 或 0，1 表示进行 gpg（GNU Private Guard）校验，0 表示不进行 gpg 校验，gpgcheck 可以确定 rpm 包的来源是有效和安全的。</li>
<li>gpgkey 为验证签名用的公钥地址，如果 gpgcheck 为 1，则必须设置 gpgkey。</li>
</ul>
<h2 id="gpgcheck-详解">gpgcheck 详解</h2>
<p><code>RPM-GPG-KEY</code> 是一个公共密钥，用于验证由该密钥签名的RPM包的真实性和完整性。在使用 <code>yum</code> 或 <code>dnf</code> 这样的包管理工具时，这些工具会使用 GPG 密钥来验证软件包的签名，以确保软件包来自于可信的源，且未被篡改。</p>
<ol>
<li>
<p><strong>命名约定：</strong> <code>RPM-GPG-KEY</code> 是一个命名约定，通常与其所属的仓库或发行版相关。例如，如果你在使用某个特定发行版的官方仓库，它可能会提供一个 <code>RPM-GPG-KEY</code> 文件来进行软件包签名验证。如openEuler官方仓库提供的 <code>RPM-GPG-KEY</code> 文件名为 <code>RPM-GPG-KEY-openEuler</code>。</p>
</li>
<li>
<p><strong>密钥生成：</strong> 这个密钥是通过 GPG（GNU Privacy Guard）工具生成的。GPG 是一个用于进行加密和签名的开源工具。<code>RPM-GPG-KEY</code> 文件包含了一个公钥，该公钥由仓库所有者使用私钥签署软件包，而用户使用公钥验证软件包。</p>
</li>
<li>
<p><strong>验证软件包：</strong> 当用户使用 <code>yum</code> 或 <code>dnf</code> 安装软件包时，这些工具会检查软件包的签名，并使用相应的 <code>RPM-GPG-KEY</code> 文件中的公钥来验证签名。如果验证通过，工具会认为软件包是可信的，否则将会发出警告或拒绝安装。</p>
</li>
<li>
<p><strong>导入密钥：</strong> 为了使用 <code>RPM-GPG-KEY</code> 文件，用户通常需要将密钥导入到本地系统中。这通常可以通过运行类似于以下命令的导入密钥的操作来完成：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-openEuler
</span></span></code></pre></div><p>上述命令中的 <code>/etc/pki/rpm-gpg/RPM-GPG-KEY-openEuler</code> 路径可能会因发行版和配置而有所不同。</p>
</li>
</ol>
<h2 id="rpm包签名">RPM包签名</h2>
<p>对于发布的 RPM 包进行 GPG 签名是一种重要的安全措施，可以确保接收者能够验证软件包的真实性和完整性。以下是一般的步骤：</p>
<ol>
<li>
<p><strong>生成 GPG 密钥：</strong> 如果你还没有 GPG 密钥对，你需要使用 GPG 工具生成一对密钥，包括私钥和公钥。你可以运行以下命令来生成密钥：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gpg --gen-key 
</span></span></code></pre></div><p>当你运行 <code>gpg --gen-key</code> 命令时，它会启动 GPG（GNU Privacy Guard）的密钥生成过程。这个过程将引导你提供一些必要的信息以生成密钥对，包括私钥和公钥。以下是这个命令的详细步骤：</p>
<ul>
<li>
<p><strong>选择密钥类型：</strong> 你将被要求选择密钥的类型。通常，默认的 RSA 和 DSA 都是可接受的选择，你可以通过键入数字来选择。</p>
</li>
<li>
<p><strong>选择密钥大小：</strong> 你将被要求选择密钥的大小。通常，默认值（通常是2048位）是足够的，但你也可以选择更大的值。</p>
</li>
<li>
<p><strong>选择密钥的有效期：</strong> 你将被要求选择密钥的有效期。你可以选择密钥永久有效，或者在一段特定的时间内有效。如果你选择了特定的时间，你需要输入一个表示有效期的值，例如1y表示一年，1m表示一个月。</p>
</li>
<li>
<p><strong>提供用户标识信息：</strong> 你将被要求提供与密钥相关联的用户标识信息。这包括你的真实姓名、电子邮件地址和一个可选的注释。</p>
</li>
<li>
<p><strong>确认提供的信息：</strong> GPG 将显示你提供的信息并询问你是否确认。如果确认无误，你可以输入 <code>O</code> 或直接按回车键。</p>
</li>
<li>
<p><strong>输入保护密语（passphrase）：</strong> 你将被要求输入保护密语，用于保护你的私钥。请确保选择一个强密码。</p>
</li>
<li>
<p><strong>等待密钥生成：</strong> GPG 将使用提供的信息生成密钥对。这可能需要一些时间，具体取决于你选择的密钥大小。</p>
</li>
<li>
<p><strong>生成完成：</strong> 一旦生成完成，你将看到一条消息表明密钥生成成功。</p>
</li>
</ul>
<p>在整个过程中，你将看到类似以下的一些提示：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gpg: key ABCDEFGH marked as ultimately trusted
</span></span><span class="line"><span class="cl">gpg: revocation certificate stored as <span class="s1">&#39;/home/your_user/.gnupg/openpgp-revocs.d/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.rev&#39;</span>
</span></span><span class="line"><span class="cl">public and secret key created and signed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">gpg: checking the trustdb
</span></span><span class="line"><span class="cl">gpg: <span class="m">3</span> marginal<span class="o">(</span>s<span class="o">)</span> needed, <span class="m">1</span> complete<span class="o">(</span>s<span class="o">)</span> needed, PGP trust model
</span></span><span class="line"><span class="cl">gpg: depth: <span class="m">0</span>  valid:   <span class="m">2</span>  signed:   <span class="m">0</span>  trust: 0-, 0q, 0n, 0m, 0f, 2u
</span></span><span class="line"><span class="cl">pub   2048R/XXXXXXXX 2024-01-01 <span class="o">[</span>expires: 2024-01-01<span class="o">]</span>
</span></span><span class="line"><span class="cl">    Key <span class="nv">fingerprint</span> <span class="o">=</span> XXXX YYYY ZZZZ AAAA BBBB  CCCC DDDD EEEE FFFF <span class="m">1111</span>
</span></span><span class="line"><span class="cl">uid                  Your Name &lt;your.email@example.com&gt;
</span></span><span class="line"><span class="cl">sub   2048R/YYYYYYYY 2024-01-01 <span class="o">[</span>expires: 2024-01-01<span class="o">]</span>
</span></span></code></pre></div><p>在这个例子中，<code>XXXXXXXX</code> 是你的密钥 ID，<code>YYYYYYYY</code> 是子密钥的 ID。你可以使用这些 ID 来引用你的密钥。</p>
</li>
<li>
<p><strong>导出公钥：</strong> 生成密钥后，你需要将公钥导出。运行以下命令：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gpg --output RPM-GPG-KEY-your-repo --armor --export your@email.com
</span></span></code></pre></div><p>这将生成一个 ASCII 格式的公钥文件 <code>RPM-GPG-KEY-your-repo</code>，你可以与软件包一起发布。</p>
</li>
<li>
<p><strong>为 RPM 包签名：</strong> 在构建 RPM 包时，使用 <code>rpmbuild</code> 命令时，可以通过添加 <code>--sign</code> 选项来指示 <code>rpmbuild</code> 对 RPM 包进行签名。例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rpmbuild -ba your-package.spec --sign
</span></span></code></pre></div><p>当你执行 <code>rpmbuild -ba your-package.spec --sign</code> 命令时，<code>rpmbuild</code> 会使用默认的 GPG 密钥进行签名。这通常是你在系统上配置为默认 GPG 密钥的密钥。</p>
<p>你可以通过检查 <code>rpmbuild</code> 使用的 GPG 密钥来确认它是哪个密钥：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rpm -q gpg-pubkey --qf <span class="s1">&#39;%{name}-%{version}-%{release} --&gt; %{summary}\n&#39;</span>
</span></span></code></pre></div><p>这个命令将显示系统上安装的 GPG 公钥，其中默认的密钥可能是 &ldquo;gpg-pubkey-xxxxxxxx-yyyyyyyy&rdquo;。你可以根据密钥的 &ldquo;xxxxxxxx-yyyyyyyy&rdquo; 部分来确定默认使用的 GPG 密钥。</p>
<p>如果你想使用不同的 GPG 密钥进行签名，可以在 <code>rpmbuild</code> 命令中使用 <code>--signwith</code> 选项，例如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rpmbuild -ba your-package.spec --signwith &lt;key-id&gt;
</span></span></code></pre></div><p>其中 <code>&lt;key-id&gt;</code> 是你想要使用的 GPG 密钥的 ID。这会覆盖默认的密钥。确保你在构建和签名 RPM 包时使用的是正确的 GPG 密钥。</p>
</li>
<li>
<p><strong>导入密钥：</strong> 为了验证你的软件包，用户需要导入你的公钥。他们可以运行以下命令：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rpm --import RPM-GPG-KEY-your-repo
</span></span></code></pre></div></li>
<li>
<p><strong>发布：</strong> 将签名的 RPM 包和公钥一起发布。确保用户知道他们可以使用导入的公钥来验证软件包的签名。</p>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Linux内核模块校验机制</title>
      <link>https://lifeislife.cn/posts/linux%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97%E6%A0%A1%E9%AA%8C%E6%9C%BA%E5%88%B6/</link>
      <pubDate>Sat, 13 Jan 2024 22:00:16 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97%E6%A0%A1%E9%AA%8C%E6%9C%BA%E5%88%B6/</guid>
      <description>&lt;p&gt;初学 Linux 内核或者第一次编译使用内核模块时经常会遇到类似这样的错误：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;insmod: ERROR: could not insert module kvm.ko: Invalid module format 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个报错通常由于当前插入&lt;code&gt;kvm.ko&lt;/code&gt;的&lt;code&gt;version magic&lt;/code&gt;版本信息与正在运行的 kernel 的&lt;code&gt;version magic&lt;/code&gt;版本不一致导致的。&lt;/p&gt;
&lt;h1 id=&#34;内核校验模块的流程&#34;&gt;内核校验模块的流程&lt;/h1&gt;
&lt;p&gt;我们从问题出发，看看内核是如何校验模块的。搜索了内核源码，找到了在函数&lt;code&gt;check_version&lt;/code&gt;中抛出了&lt;code&gt;disagrees about version of symbol&lt;/code&gt;错误信息，我们根据源码来回溯一下整个过程。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// kernel/module.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s32&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;Elf_Shdr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sechdrs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sechdrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;versindex&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modversion_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* Exporting module didn&amp;#39;t supply crcs?  OK, we&amp;#39;re already tainted. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* No versions at all?  modprobe --force does this. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versindex&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;try_to_force_load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sechdrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versindex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;num_versions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sechdrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versindex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh_size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modversion_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;strcmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;IS_ENABLED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CONFIG_MODULE_REL_CRCS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;resolve_rel_crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;pr_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Found checksum %X vs module %lX&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bad_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* Broken toolchain. Warn once, then let it go.. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;nf&#34;&gt;pr_warn_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s: no symbol version for %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;bad_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;nf&#34;&gt;pr_warn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s: disagrees about version of symbol %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参数说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;info: 包含正在加载信息的结构体。&lt;/li&gt;
&lt;li&gt;symname: 需要查找对比的符号的名称。&lt;/li&gt;
&lt;li&gt;mod: 表示模块的结构体。&lt;/li&gt;
&lt;li&gt;crc: 当前正在运行的内核的模块符号的 CRC（Cyclic Redundancy Check）值&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;如果 CRC 为空，不检查直接 PASS&lt;/li&gt;
&lt;li&gt;如果模块中没有_versions 小节，表示模块没有开启 CRC
&lt;ol&gt;
&lt;li&gt;如果开启了 CONFIG_MODULE_FORCE_LOAD，则强制加载，内核标记为 tainted，直接 PASS&lt;/li&gt;
&lt;li&gt;如果没有开启 CONFIG_MODULE_FORCE_LOAD，则报错&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;如果模块中有_versions 小节，没有找到 module_layout 符号，报 warning，直接 PASS&lt;/li&gt;
&lt;li&gt;如果模块中有_versions 小节，找到 module_layout 符号
&lt;ol&gt;
&lt;li&gt;对比_versions 小节中的 CRC 和参数中的 CRC，如果一致，PASS&lt;/li&gt;
&lt;li&gt;如果不一致，报错&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;插播一句，CRC是什么？在 Linux 内核中，模块符号 CRC（Cyclic Redundancy Check）是一种校验值，用于确保模块中的符号（函数、变量等）在加载时与内核中的符号一致。当模块被构建时，针对每个符号都会计算一个 CRC 值，然后将这些 CRC 值保存在模块的符号版本表中。简单理解就是如果要保持CRC不变，需要满足两个条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;语法保持不变
遵守这个条件，说明如果模块在新内核下重新编译，那应该没有任何语法问题。 即导出符号的类型名没有变化，如果是函数，则要求参数和返回值类型没有任何变化；如果这些类型是结构体的话，结构体的成员名也没有有任何变化。&lt;/li&gt;
&lt;li&gt;语义保持不变
这要求符号的类型不能有变化，如果类型本身是结构体(struct)，则它成员的类型不能有变化，成员在结构体内的位置不能有变化，以及成员本身不能增删。
如果想要深入了解如何计算CRC可以参考这篇博客：&lt;a href=&#34;https://blog.csdn.net/linyt/article/details/42559639&#34;&gt;Linux内核模块符号CRC检查机制-CSDN博客&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;分析代码我们可以知道，内核会通过遍历正在加载的模块的版本信息的数组&lt;code&gt;versions&lt;/code&gt;，从中查找与给定符号名称匹配的版本信息。如果找到匹配的版本信息，则计算 CRC 值，与参数中的 CRC 值进行比较。（通过后续分析我们知道参数的 CRC 就是正在运行的内核的 module_layout 符号的 CRC）如果匹配，表示版本一致，返回 1。如果不匹配，打印调试信息，并跳转到 &lt;code&gt;bad_version&lt;/code&gt;，输出警告信息。&lt;/p&gt;
&lt;p&gt;这里有两个疑问，&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;versions&lt;/code&gt; 内容是怎么链接到模块的 elf 文件中的？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们找到模块的&lt;code&gt;mod.c&lt;/code&gt;文件，打开可以发现以下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;MODULE_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vermagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;VERMAGIC_STRING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;MODULE_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KBUILD_MODNAME&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;__visible&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__this_module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;__section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linkonce&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;this_module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KBUILD_MODNAME&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;init_module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_MODULE_UNLOAD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cleanup_module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arch&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MODULE_ARCH_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_RETPOLINE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;MODULE_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;retpoline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Y&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modversion_info&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;____versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;__used&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x3e549f1d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;module_layout&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x5138e6ba&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;param_ops_int&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x183b57f9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;phy_ethtool_nway_reset&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x6e5363eb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;eth_validate_addr&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x4df55e5b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;usb_deregister&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x8e48f69b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;usb_register_driver&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个文件是在编译过程中调用了&lt;code&gt;scripts/modpost&lt;/code&gt;脚本生成的，它的功能是在里面增加了 2 个&lt;code&gt;__section&lt;/code&gt;，&lt;code&gt;.gnu.linkonce.this_module&lt;/code&gt;和&lt;code&gt;__versions&lt;/code&gt;。__versions 小节的内容就是一些字符串和值组成的数组，&lt;code&gt;check_version&lt;/code&gt;就是解析这个小节去做验证。&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;CRC 值哪来的？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们继续向上跟踪，找到函数&lt;code&gt;check_modstruct_version&lt;/code&gt;，其中&lt;code&gt;find_symbol&lt;/code&gt;会在内核符号表中查找给定符号名称的符号信息，接着调用&lt;code&gt;check_version&lt;/code&gt;函数，传入符号名称、模块结构体和 CRC 值，进行版本匹配。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// kernel/module.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;inline&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_modstruct_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s32&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;  * Since this should be found in kernel (which can&amp;#39;t be removed), no
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;  * locking is necessary -- use preempt_disable() to placate lockdep.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;nf&#34;&gt;preempt_disable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;find_symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;module_layout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;preempt_enable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;BUG&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;nf&#34;&gt;preempt_enable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;module_layout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 获取当前运行内核 module_layout 函数的 crc 值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;find_symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;module_layout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;each_symbol_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find_exported_symbol_in_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fsa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 遍历内核三个导出符号表段__start___ksymtab，__start___ksymtab_gpl 和__start___ksymtab_gpl_future，为每段调用 find_symbol_in_section
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;each_symbol_in_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ARRAY_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 遍历内核每个已加载模块的三个导出符号表段 mod-&amp;gt;syms,mod-&amp;gt;gpl_syms,mod-&amp;gt;gpl_future_syms，为每段调用 find_symbol_in_section
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;each_symbol_in_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ARRAY_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// 对导出符号表进行二分查找，按照字符串排序，符号表的地址按照地址排序
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;find_exported_symbol_in_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symsearch&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Linux 对可装载模块采取了两层验证&lt;/strong&gt;：除了上述的模块 CRC 值校验外还有 &lt;code&gt;vermagic&lt;/code&gt; 的检查。模块 vermagic（即 Version Magic String）保存了模块编译时的内核版本以及 SMP 等配置信息，当模块 vermagic 与主机信息不相符时也无法加载模块。&lt;/p&gt;
&lt;p&gt;在内核中&lt;code&gt;load_module&lt;/code&gt;函数调用&lt;code&gt;check_modstruct_version&lt;/code&gt;函数完成 CRC 校验后，就会继续调用&lt;code&gt;layout_and_allocate --&amp;gt; check_modinfo&lt;/code&gt; 完成 vermagic 校验。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// kernel/module.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_modinfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_modinfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;vermagic&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MODULE_INIT_IGNORE_VERMAGIC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* This is allowed: modprobe --force will invalidate it. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;try_to_force_load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;bad vermagic&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;same_magic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vermagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;pr_err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s: version magic &amp;#39;%s&amp;#39; should be &amp;#39;%s&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vermagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENOEXEC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;get_modinfo&lt;/code&gt; 会获取内核中的 vermagic 信息，模块 vermagic 信息则被保存在了 ELF 的 &lt;code&gt;.modinfo&lt;/code&gt; 小节中。这里我们说的 vermagic 就是下文提到的拓展版本信息，它就是系统配置信息组成的一个字符串。&lt;/p&gt;
&lt;h1 id=&#34;如何解决模块校验错误&#34;&gt;如何解决模块校验错误&lt;/h1&gt;
&lt;p&gt;Linux 对可装载模块采取了两层验证，我们需要分别从 CRC 和 vermagic 两个方面来解决模块校验错误。首先从简单的 vermagic 校验开始。我们需要保证运行的内核版本与模块编译时的内核版本一致，这样才能保证 vermagic 校验通过。首先了解如何查看内核版本以及模块版本信息，然后修改内核模块版本信息。&lt;/p&gt;
&lt;h2 id=&#34;解决-vermagic-校验错误&#34;&gt;解决 vermagic 校验错误&lt;/h2&gt;
&lt;h3 id=&#34;如何查看内核版本以及模块版本信息&#34;&gt;如何查看内核版本以及模块版本信息&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;uname&lt;/code&gt;参数功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-s, 输出 kernel 名称；&lt;/li&gt;
&lt;li&gt;-n, 输出主机名；&lt;/li&gt;
&lt;li&gt;-r, 输出 kernel 发行版本号；&lt;/li&gt;
&lt;li&gt;-v, 输出操作系统版本；&lt;/li&gt;
&lt;li&gt;-m, 输出主机的硬件架构名称；&lt;/li&gt;
&lt;li&gt;-p, 输出处理器类型；&lt;/li&gt;
&lt;li&gt;-i, 输出硬件平台；&lt;/li&gt;
&lt;li&gt;-o, 输出操作系统名称&lt;/li&gt;
&lt;li&gt;-a, 输出所有信息&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输出kernel发行版本号&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uname -r
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6.4.0-10.1.0.20.oe2309.riscv64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输出所有信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uname -a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Linux openeuler 6.4.0-10.1.0.20.oe2309.riscv64 &lt;span class=&#34;c1&#34;&gt;#1 SMP Sat Oct  7 06:19:28 UTC 2023 riscv64 riscv64 riscv64 GNU/Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;modinfo 可以查看模块信息，包括模块vermagic信息。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;modinfo kvm.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;filename:       /root/build-kernel/kernel/./arch/riscv/kvm/kvm.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;license:        GPL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;author:         Qumranet
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;srcversion:     5DA13DC0E55100B5FE1D56A
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;depends:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;intree:         Y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;name:           kvm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vermagic:       6.4.0 SMP mod_unload modversions riscv
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parm:           halt_poll_ns:uint
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parm:           halt_poll_ns_grow:uint
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parm:           halt_poll_ns_grow_start:uint
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parm:           halt_poll_ns_shrink:uint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中&lt;code&gt;vermagic&lt;/code&gt;就是&lt;code&gt;version magic&lt;/code&gt;版本信息，可以看到当前&lt;code&gt;kvm.ko&lt;/code&gt;的&lt;code&gt;version magic&lt;/code&gt;版本信息为&lt;code&gt;6.4.0&lt;/code&gt;。与前文的&lt;code&gt;uname -r&lt;/code&gt;输出的 kernel 发行版本号&lt;code&gt;6.4.0-10.1.0.20.oe2309.riscv64&lt;/code&gt;不一致。所以会报错。&lt;/p&gt;
&lt;h3 id=&#34;修改内核模块版本信息&#34;&gt;修改内核模块版本信息&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;修改基础版本信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;打开内核源代码根目录下的 Makefile 文件。你会找到一个包含内核版本信息的地方，类似于：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Makefile&#34; data-lang=&#34;Makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# SPDX-License-Identifier: GPL-2.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;VERSION&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PATCHLEVEL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SUBLEVEL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;EXTRAVERSION&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;表示内核版基础本号为&lt;code&gt;6.4.0&lt;/code&gt;。&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;修改拓展版本信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;kernel 引入了一些配置来增强版本信息，在内核源码的&lt;code&gt;&amp;quot;include/linux/vermagic.h&amp;quot;&lt;/code&gt;下我们可以看到模块的健全版本信息，如下默认配置的有：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Simply sanity version stamp for modules. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_SMP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_SMP &amp;#34;SMP &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_SMP &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_PREEMPT_BUILD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_PREEMPT &amp;#34;preempt &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#elif defined(CONFIG_PREEMPT_RT)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_PREEMPT &amp;#34;preempt_rt &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_PREEMPT &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_MODULE_UNLOAD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_MODULE_UNLOAD &amp;#34;mod_unload &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_MODULE_UNLOAD &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_MODVERSIONS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_MODVERSIONS &amp;#34;modversions &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_MODVERSIONS &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef RANDSTRUCT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;generated/randstruct_hash.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_RANDSTRUCT &amp;#34;RANDSTRUCT_&amp;#34; RANDSTRUCT_HASHED_SEED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_RANDSTRUCT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define VERMAGIC_STRING                                                 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        UTS_RELEASE &amp;#34; &amp;#34;                                                 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                     \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS       \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MODULE_ARCH_VERMAGIC                                            \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MODULE_RANDSTRUCT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，&lt;code&gt;&amp;quot;UTS_RELEASE&amp;quot;&lt;/code&gt;的配置在内核源码的&lt;code&gt;&amp;quot;include/generated/utsrelease.h&amp;quot;&lt;/code&gt;下可以看到，&lt;code&gt;utsrelease.h&lt;/code&gt;的内容是由&lt;code&gt;Makefile&lt;/code&gt;和``.config&lt;code&gt;的内容来生成的，当成功编译kernel以后，&lt;/code&gt;utsrelease.h`得到更新，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#defineUTS_RELEASE &amp;#34;6.4.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么前文&amp;quot;6.4.0-d46299ae&amp;quot;中的&amp;quot;-d46299ae&amp;quot;是如何得来的呢？其实这个是开发者使用了 Git 来管理代码。当你修改或者提交代码以后，每次编译内核后，在&amp;quot;UTS_RELEASE&amp;quot;后面就会看到一串哈希值，例如&amp;quot;6.4.0-d46299ae&amp;quot;，其中&amp;quot;-d46299ae&amp;quot;这个就是 Git 版本控制而产生的哈希值。发行版本号只是各个厂商用于区别自己发布的不同时期的 kernel 版本或者产品版本而产生的编号，完全由各厂商自己定义。&lt;/p&gt;
&lt;h2 id=&#34;解决-crc-校验错误&#34;&gt;解决 CRC 校验错误&lt;/h2&gt;
&lt;p&gt;我们可以通过一些手段修改新模块的 module_layout 的 CRC 与内核CRC相同，再插入。&lt;code&gt;/boot&lt;/code&gt;目录下通常有个在&lt;code&gt;symvers-&amp;lt;kernel_version&amp;gt;.gz&lt;/code&gt; 文件通常包含了内核模块的符号版本信息。这个文件是由 Linux 内核构建时生成的，用于记录在该内核版本下构建的模块的符号信息，包括函数和变量的名称、版本号等。里面就保存了内核的 module_layout 的 CRC 值。我们可以使用&lt;code&gt;gzip -d&lt;/code&gt;命令解压这个文件，找到 module_layout 的 CRC 值，记录下来。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;方法一：使用 16 进制编辑器修改模块文件，将 module_layout 的值修改为相同的值，再插入。
在 Linux 中，可以使用 &lt;code&gt;hexdump&lt;/code&gt; 和 &lt;code&gt;xxd&lt;/code&gt; 等工具查看二进制文件的内容，并尝试编辑。下面是一种使用 &lt;code&gt;xxd&lt;/code&gt; 查看和修改二进制文件的方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;使用 &lt;code&gt;xxd&lt;/code&gt; 将二进制文件转换为十六进制文本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xxd /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko &amp;gt; kvm_hex.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这将创建一个名为 &lt;code&gt;kvm_hex.txt&lt;/code&gt; 的文本文件，其中包含 &lt;code&gt;kvm.ko&lt;/code&gt; 的十六进制表示。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用文本编辑器（如 &lt;code&gt;nano&lt;/code&gt; 或 &lt;code&gt;vim&lt;/code&gt;）打开 &lt;code&gt;kvm_hex.txt&lt;/code&gt;，找到并编辑 &lt;code&gt;module_layout&lt;/code&gt; 的值。请确保你了解所做更改的含义，并且只修改你确信的内容。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;保存并关闭文本编辑器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 &lt;code&gt;xxd&lt;/code&gt; 将修改后的十六进制文本转换回二进制文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xxd -r kvm_hex.txt &amp;gt; /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这将覆盖原始的 &lt;code&gt;kvm.ko&lt;/code&gt; 文件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;方法二：修改 Module.symvers&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理编译结果。不要使用 make distclean，这会删除.config 文件以及 Module.symvers 文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 修改 Module.symvers 文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sed -i  &lt;span class=&#34;s1&#34;&gt;&amp;#39;/module_layout/ s/0x[0-9a-f][0-9a-f]*/0xdf88831e/&amp;#39;&lt;/span&gt; Module.symvers
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 重新编译模块&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;M&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./arch/riscv/kvm/ -j33
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 检查模块的 module_layout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;modprobe --dump-modversions /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep module_layout
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0xdf88831e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;如何生成-modc-文件&#34;&gt;如何生成 .mod.c 文件&lt;/h1&gt;
&lt;p&gt;如果是自己写的模块，可以根据下面的命令编译模块，就可以得到&lt;code&gt;.mod.c&lt;/code&gt;文件，它是源文件到&lt;code&gt;.mod.o&lt;/code&gt;文件的一个中间文件。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make -C /root/build-kernel/kernel &lt;span class=&#34;nv&#34;&gt;M&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/driver_study/ modules -j22
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果是用内核自己的模块，执行&lt;code&gt;make modules&lt;/code&gt;命令，也可以得到&lt;code&gt;.mod.c&lt;/code&gt;文件。但是一般执行&lt;code&gt;make -j22&lt;/code&gt;命令就不会生成这些文件，我们可以找一个启用的内核模块，例如&lt;code&gt;kvm.ko&lt;/code&gt;，执行下面的命令，就可以得到&lt;code&gt;.mod.c&lt;/code&gt;文件。不能随便找个模块，必须在 config 中开启的模块，否则会报错&lt;code&gt;undefined!&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make  &lt;span class=&#34;nv&#34;&gt;M&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./arch/riscv/kvm modules -j22
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>初学 Linux 内核或者第一次编译使用内核模块时经常会遇到类似这样的错误：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">insmod: ERROR: could not insert module kvm.ko: Invalid module format 
</span></span></code></pre></div><p>这个报错通常由于当前插入<code>kvm.ko</code>的<code>version magic</code>版本信息与正在运行的 kernel 的<code>version magic</code>版本不一致导致的。</p>
<h1 id="内核校验模块的流程">内核校验模块的流程</h1>
<p>我们从问题出发，看看内核是如何校验模块的。搜索了内核源码，找到了在函数<code>check_version</code>中抛出了<code>disagrees about version of symbol</code>错误信息，我们根据源码来回溯一下整个过程。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// kernel/module.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">check_version</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">load_info</span> <span class="o">*</span><span class="n">info</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">symname</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">mod</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="n">s32</span> <span class="o">*</span><span class="n">crc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Elf_Shdr</span> <span class="o">*</span><span class="n">sechdrs</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">sechdrs</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">versindex</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">index</span><span class="p">.</span><span class="n">vers</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">num_versions</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">modversion_info</span> <span class="o">*</span><span class="n">versions</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/* Exporting module didn&#39;t supply crcs?  OK, we&#39;re already tainted. */</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">crc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/* No versions at all?  modprobe --force does this. */</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">versindex</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nf">try_to_force_load</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">symname</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">versions</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span> <span class="n">sechdrs</span><span class="p">[</span><span class="n">versindex</span><span class="p">].</span><span class="n">sh_addr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">num_versions</span> <span class="o">=</span> <span class="n">sechdrs</span><span class="p">[</span><span class="n">versindex</span><span class="p">].</span><span class="n">sh_size</span>
</span></span><span class="line"><span class="cl">  <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">modversion_info</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">num_versions</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">u32</span> <span class="n">crcval</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nf">strcmp</span><span class="p">(</span><span class="n">versions</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">name</span><span class="p">,</span> <span class="n">symname</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nf">IS_ENABLED</span><span class="p">(</span><span class="n">CONFIG_MODULE_REL_CRCS</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">   <span class="n">crcval</span> <span class="o">=</span> <span class="nf">resolve_rel_crc</span><span class="p">(</span><span class="n">crc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="cl">   <span class="n">crcval</span> <span class="o">=</span> <span class="o">*</span><span class="n">crc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="n">versions</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">crc</span> <span class="o">==</span> <span class="n">crcval</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pr_debug</span><span class="p">(</span><span class="s">&#34;Found checksum %X vs module %lX</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">crcval</span><span class="p">,</span> <span class="n">versions</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">crc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">goto</span> <span class="n">bad_version</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/* Broken toolchain. Warn once, then let it go.. */</span>
</span></span><span class="line"><span class="cl"> <span class="nf">pr_warn_once</span><span class="p">(</span><span class="s">&#34;%s: no symbol version for %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">symname</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nl">bad_version</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nf">pr_warn</span><span class="p">(</span><span class="s">&#34;%s: disagrees about version of symbol %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">info</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">symname</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>参数说明：</p>
<ul>
<li>info: 包含正在加载信息的结构体。</li>
<li>symname: 需要查找对比的符号的名称。</li>
<li>mod: 表示模块的结构体。</li>
<li>crc: 当前正在运行的内核的模块符号的 CRC（Cyclic Redundancy Check）值</li>
</ul>
<ol>
<li>如果 CRC 为空，不检查直接 PASS</li>
<li>如果模块中没有_versions 小节，表示模块没有开启 CRC
<ol>
<li>如果开启了 CONFIG_MODULE_FORCE_LOAD，则强制加载，内核标记为 tainted，直接 PASS</li>
<li>如果没有开启 CONFIG_MODULE_FORCE_LOAD，则报错</li>
</ol>
</li>
<li>如果模块中有_versions 小节，没有找到 module_layout 符号，报 warning，直接 PASS</li>
<li>如果模块中有_versions 小节，找到 module_layout 符号
<ol>
<li>对比_versions 小节中的 CRC 和参数中的 CRC，如果一致，PASS</li>
<li>如果不一致，报错</li>
</ol>
</li>
</ol>
<blockquote>
<p>插播一句，CRC是什么？在 Linux 内核中，模块符号 CRC（Cyclic Redundancy Check）是一种校验值，用于确保模块中的符号（函数、变量等）在加载时与内核中的符号一致。当模块被构建时，针对每个符号都会计算一个 CRC 值，然后将这些 CRC 值保存在模块的符号版本表中。简单理解就是如果要保持CRC不变，需要满足两个条件：</p>
<ol>
<li>语法保持不变
遵守这个条件，说明如果模块在新内核下重新编译，那应该没有任何语法问题。 即导出符号的类型名没有变化，如果是函数，则要求参数和返回值类型没有任何变化；如果这些类型是结构体的话，结构体的成员名也没有有任何变化。</li>
<li>语义保持不变
这要求符号的类型不能有变化，如果类型本身是结构体(struct)，则它成员的类型不能有变化，成员在结构体内的位置不能有变化，以及成员本身不能增删。
如果想要深入了解如何计算CRC可以参考这篇博客：<a href="https://blog.csdn.net/linyt/article/details/42559639">Linux内核模块符号CRC检查机制-CSDN博客</a></li>
</ol>
</blockquote>
<p>分析代码我们可以知道，内核会通过遍历正在加载的模块的版本信息的数组<code>versions</code>，从中查找与给定符号名称匹配的版本信息。如果找到匹配的版本信息，则计算 CRC 值，与参数中的 CRC 值进行比较。（通过后续分析我们知道参数的 CRC 就是正在运行的内核的 module_layout 符号的 CRC）如果匹配，表示版本一致，返回 1。如果不匹配，打印调试信息，并跳转到 <code>bad_version</code>，输出警告信息。</p>
<p>这里有两个疑问，</p>
<ol>
<li><code>versions</code> 内容是怎么链接到模块的 elf 文件中的？</li>
</ol>
<p>我们找到模块的<code>mod.c</code>文件，打开可以发现以下内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">MODULE_INFO</span><span class="p">(</span><span class="n">vermagic</span><span class="p">,</span> <span class="n">VERMAGIC_STRING</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nf">MODULE_INFO</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">KBUILD_MODNAME</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">__visible</span> <span class="k">struct</span> <span class="n">module</span> <span class="n">__this_module</span>
</span></span><span class="line"><span class="cl"><span class="nf">__section</span><span class="p">(.</span><span class="n">gnu</span><span class="p">.</span><span class="n">linkonce</span><span class="p">.</span><span class="n">this_module</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">KBUILD_MODNAME</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">init</span> <span class="o">=</span> <span class="n">init_module</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_MODULE_UNLOAD
</span></span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">exit</span> <span class="o">=</span> <span class="n">cleanup_module</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">arch</span> <span class="o">=</span> <span class="n">MODULE_ARCH_INIT</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_RETPOLINE
</span></span></span><span class="line"><span class="cl"><span class="nf">MODULE_INFO</span><span class="p">(</span><span class="n">retpoline</span><span class="p">,</span> <span class="s">&#34;Y&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">modversion_info</span> <span class="n">____versions</span><span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">__used</span> <span class="nf">__section</span><span class="p">(</span><span class="n">__versions</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x3e549f1d</span><span class="p">,</span> <span class="s">&#34;module_layout&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x5138e6ba</span><span class="p">,</span> <span class="s">&#34;param_ops_int&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x183b57f9</span><span class="p">,</span> <span class="s">&#34;phy_ethtool_nway_reset&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x6e5363eb</span><span class="p">,</span> <span class="s">&#34;eth_validate_addr&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x4df55e5b</span><span class="p">,</span> <span class="s">&#34;usb_deregister&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x8e48f69b</span><span class="p">,</span> <span class="s">&#34;usb_register_driver&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这个文件是在编译过程中调用了<code>scripts/modpost</code>脚本生成的，它的功能是在里面增加了 2 个<code>__section</code>，<code>.gnu.linkonce.this_module</code>和<code>__versions</code>。__versions 小节的内容就是一些字符串和值组成的数组，<code>check_version</code>就是解析这个小节去做验证。</p>
<ol start="2">
<li>CRC 值哪来的？</li>
</ol>
<p>我们继续向上跟踪，找到函数<code>check_modstruct_version</code>，其中<code>find_symbol</code>会在内核符号表中查找给定符号名称的符号信息，接着调用<code>check_version</code>函数，传入符号名称、模块结构体和 CRC 值，进行版本匹配。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// kernel/module.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">check_modstruct_version</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">load_info</span> <span class="o">*</span><span class="n">info</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">       <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">mod</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">s32</span> <span class="o">*</span><span class="n">crc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">  * Since this should be found in kernel (which can&#39;t be removed), no
</span></span></span><span class="line"><span class="cl"><span class="cm">  * locking is necessary -- use preempt_disable() to placate lockdep.
</span></span></span><span class="line"><span class="cl"><span class="cm">  */</span>
</span></span><span class="line"><span class="cl"> <span class="nf">preempt_disable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">find_symbol</span><span class="p">(</span><span class="s">&#34;module_layout&#34;</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">crc</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span> <span class="nb">false</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">preempt_enable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nf">BUG</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nf">preempt_enable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nf">check_version</span><span class="p">(</span><span class="n">info</span><span class="p">,</span> <span class="s">&#34;module_layout&#34;</span><span class="p">,</span> <span class="n">mod</span><span class="p">,</span> <span class="n">crc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 获取当前运行内核 module_layout 函数的 crc 值
</span></span></span><span class="line"><span class="cl"><span class="nf">find_symbol</span><span class="p">(</span><span class="s">&#34;module_layout&#34;</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">crc</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span> <span class="nb">false</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nf">each_symbol_section</span><span class="p">(</span><span class="n">find_exported_symbol_in_section</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fsa</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 遍历内核三个导出符号表段__start___ksymtab，__start___ksymtab_gpl 和__start___ksymtab_gpl_future，为每段调用 find_symbol_in_section
</span></span></span><span class="line"><span class="cl">        <span class="nf">each_symbol_in_section</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="nf">ARRAY_SIZE</span><span class="p">(</span><span class="n">arr</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">fn</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 遍历内核每个已加载模块的三个导出符号表段 mod-&gt;syms,mod-&gt;gpl_syms,mod-&gt;gpl_future_syms，为每段调用 find_symbol_in_section
</span></span></span><span class="line"><span class="cl">        <span class="nf">each_symbol_in_section</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="nf">ARRAY_SIZE</span><span class="p">(</span><span class="n">arr</span><span class="p">),</span> <span class="n">mod</span><span class="p">,</span> <span class="n">fn</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 对导出符号表进行二分查找，按照字符串排序，符号表的地址按照地址排序
</span></span></span><span class="line"><span class="cl">            <span class="nf">find_exported_symbol_in_section</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">symsearch</span> <span class="o">*</span><span class="n">syms</span><span class="p">,</span><span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">,</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
</span></span></code></pre></div><p><strong>Linux 对可装载模块采取了两层验证</strong>：除了上述的模块 CRC 值校验外还有 <code>vermagic</code> 的检查。模块 vermagic（即 Version Magic String）保存了模块编译时的内核版本以及 SMP 等配置信息，当模块 vermagic 与主机信息不相符时也无法加载模块。</p>
<p>在内核中<code>load_module</code>函数调用<code>check_modstruct_version</code>函数完成 CRC 校验后，就会继续调用<code>layout_and_allocate --&gt; check_modinfo</code> 完成 vermagic 校验。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// kernel/module.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">check_modinfo</span><span class="p">(</span><span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">mod</span><span class="p">,</span> <span class="k">struct</span> <span class="n">load_info</span> <span class="o">*</span><span class="n">info</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">modmagic</span> <span class="o">=</span> <span class="nf">get_modinfo</span><span class="p">(</span><span class="n">info</span><span class="p">,</span> <span class="s">&#34;vermagic&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">err</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">MODULE_INIT_IGNORE_VERMAGIC</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">modmagic</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/* This is allowed: modprobe --force will invalidate it. */</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">modmagic</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">err</span> <span class="o">=</span> <span class="nf">try_to_force_load</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="s">&#34;bad vermagic&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="n">err</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">same_magic</span><span class="p">(</span><span class="n">modmagic</span><span class="p">,</span> <span class="n">vermagic</span><span class="p">,</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">index</span><span class="p">.</span><span class="n">vers</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pr_err</span><span class="p">(</span><span class="s">&#34;%s: version magic &#39;%s&#39; should be &#39;%s&#39;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">         <span class="n">info</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">modmagic</span><span class="p">,</span> <span class="n">vermagic</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="o">-</span><span class="n">ENOEXEC</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>get_modinfo</code> 会获取内核中的 vermagic 信息，模块 vermagic 信息则被保存在了 ELF 的 <code>.modinfo</code> 小节中。这里我们说的 vermagic 就是下文提到的拓展版本信息，它就是系统配置信息组成的一个字符串。</p>
<h1 id="如何解决模块校验错误">如何解决模块校验错误</h1>
<p>Linux 对可装载模块采取了两层验证，我们需要分别从 CRC 和 vermagic 两个方面来解决模块校验错误。首先从简单的 vermagic 校验开始。我们需要保证运行的内核版本与模块编译时的内核版本一致，这样才能保证 vermagic 校验通过。首先了解如何查看内核版本以及模块版本信息，然后修改内核模块版本信息。</p>
<h2 id="解决-vermagic-校验错误">解决 vermagic 校验错误</h2>
<h3 id="如何查看内核版本以及模块版本信息">如何查看内核版本以及模块版本信息</h3>
<p><code>uname</code>参数功能：</p>
<ul>
<li>-s, 输出 kernel 名称；</li>
<li>-n, 输出主机名；</li>
<li>-r, 输出 kernel 发行版本号；</li>
<li>-v, 输出操作系统版本；</li>
<li>-m, 输出主机的硬件架构名称；</li>
<li>-p, 输出处理器类型；</li>
<li>-i, 输出硬件平台；</li>
<li>-o, 输出操作系统名称</li>
<li>-a, 输出所有信息</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 输出kernel发行版本号</span>
</span></span><span class="line"><span class="cl">uname -r
</span></span><span class="line"><span class="cl">6.4.0-10.1.0.20.oe2309.riscv64
</span></span><span class="line"><span class="cl"><span class="c1"># 输出所有信息</span>
</span></span><span class="line"><span class="cl">uname -a
</span></span><span class="line"><span class="cl">Linux openeuler 6.4.0-10.1.0.20.oe2309.riscv64 <span class="c1">#1 SMP Sat Oct  7 06:19:28 UTC 2023 riscv64 riscv64 riscv64 GNU/Linux</span>
</span></span></code></pre></div><p>modinfo 可以查看模块信息，包括模块vermagic信息。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">modinfo kvm.ko
</span></span><span class="line"><span class="cl">filename:       /root/build-kernel/kernel/./arch/riscv/kvm/kvm.ko
</span></span><span class="line"><span class="cl">license:        GPL
</span></span><span class="line"><span class="cl">author:         Qumranet
</span></span><span class="line"><span class="cl">srcversion:     5DA13DC0E55100B5FE1D56A
</span></span><span class="line"><span class="cl">depends:
</span></span><span class="line"><span class="cl">intree:         Y
</span></span><span class="line"><span class="cl">name:           kvm
</span></span><span class="line"><span class="cl">vermagic:       6.4.0 SMP mod_unload modversions riscv
</span></span><span class="line"><span class="cl">parm:           halt_poll_ns:uint
</span></span><span class="line"><span class="cl">parm:           halt_poll_ns_grow:uint
</span></span><span class="line"><span class="cl">parm:           halt_poll_ns_grow_start:uint
</span></span><span class="line"><span class="cl">parm:           halt_poll_ns_shrink:uint
</span></span></code></pre></div><p>其中<code>vermagic</code>就是<code>version magic</code>版本信息，可以看到当前<code>kvm.ko</code>的<code>version magic</code>版本信息为<code>6.4.0</code>。与前文的<code>uname -r</code>输出的 kernel 发行版本号<code>6.4.0-10.1.0.20.oe2309.riscv64</code>不一致。所以会报错。</p>
<h3 id="修改内核模块版本信息">修改内核模块版本信息</h3>
<ol>
<li>修改基础版本信息</li>
</ol>
<p>打开内核源代码根目录下的 Makefile 文件。你会找到一个包含内核版本信息的地方，类似于：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Makefile" data-lang="Makefile"><span class="line"><span class="cl"><span class="c"># SPDX-License-Identifier: GPL-2.0
</span></span></span><span class="line"><span class="cl"><span class="nv">VERSION</span> <span class="o">=</span> <span class="m">6</span>
</span></span><span class="line"><span class="cl"><span class="nv">PATCHLEVEL</span> <span class="o">=</span> <span class="m">4</span>
</span></span><span class="line"><span class="cl"><span class="nv">SUBLEVEL</span> <span class="o">=</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="nv">EXTRAVERSION</span> <span class="o">=</span>
</span></span></code></pre></div><p>表示内核版基础本号为<code>6.4.0</code>。</p>
<ol start="2">
<li>修改拓展版本信息</li>
</ol>
<p>kernel 引入了一些配置来增强版本信息，在内核源码的<code>&quot;include/linux/vermagic.h&quot;</code>下我们可以看到模块的健全版本信息，如下默认配置的有：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* Simply sanity version stamp for modules. */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_SMP
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_SMP &#34;SMP &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_SMP &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_PREEMPT_BUILD
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_PREEMPT &#34;preempt &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#elif defined(CONFIG_PREEMPT_RT)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_PREEMPT &#34;preempt_rt &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_PREEMPT &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_MODULE_UNLOAD
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_MODULE_UNLOAD &#34;mod_unload &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_MODULE_UNLOAD &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_MODVERSIONS
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_MODVERSIONS &#34;modversions &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_MODVERSIONS &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp">#ifdef RANDSTRUCT
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;generated/randstruct_hash.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_RANDSTRUCT &#34;RANDSTRUCT_&#34; RANDSTRUCT_HASHED_SEED
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_RANDSTRUCT
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#define VERMAGIC_STRING                                                 \
</span></span></span><span class="line"><span class="cl"><span class="cp">        UTS_RELEASE &#34; &#34;                                                 \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                     \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS       \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MODULE_ARCH_VERMAGIC                                            \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MODULE_RANDSTRUCT
</span></span></span></code></pre></div><p>其中，<code>&quot;UTS_RELEASE&quot;</code>的配置在内核源码的<code>&quot;include/generated/utsrelease.h&quot;</code>下可以看到，<code>utsrelease.h</code>的内容是由<code>Makefile</code>和``.config<code>的内容来生成的，当成功编译kernel以后，</code>utsrelease.h`得到更新，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#defineUTS_RELEASE &#34;6.4.0&#34;</span>
</span></span></code></pre></div><p>那么前文&quot;6.4.0-d46299ae&quot;中的&quot;-d46299ae&quot;是如何得来的呢？其实这个是开发者使用了 Git 来管理代码。当你修改或者提交代码以后，每次编译内核后，在&quot;UTS_RELEASE&quot;后面就会看到一串哈希值，例如&quot;6.4.0-d46299ae&quot;，其中&quot;-d46299ae&quot;这个就是 Git 版本控制而产生的哈希值。发行版本号只是各个厂商用于区别自己发布的不同时期的 kernel 版本或者产品版本而产生的编号，完全由各厂商自己定义。</p>
<h2 id="解决-crc-校验错误">解决 CRC 校验错误</h2>
<p>我们可以通过一些手段修改新模块的 module_layout 的 CRC 与内核CRC相同，再插入。<code>/boot</code>目录下通常有个在<code>symvers-&lt;kernel_version&gt;.gz</code> 文件通常包含了内核模块的符号版本信息。这个文件是由 Linux 内核构建时生成的，用于记录在该内核版本下构建的模块的符号信息，包括函数和变量的名称、版本号等。里面就保存了内核的 module_layout 的 CRC 值。我们可以使用<code>gzip -d</code>命令解压这个文件，找到 module_layout 的 CRC 值，记录下来。</p>
<ul>
<li>
<p>方法一：使用 16 进制编辑器修改模块文件，将 module_layout 的值修改为相同的值，再插入。
在 Linux 中，可以使用 <code>hexdump</code> 和 <code>xxd</code> 等工具查看二进制文件的内容，并尝试编辑。下面是一种使用 <code>xxd</code> 查看和修改二进制文件的方法：</p>
<ol>
<li>
<p>使用 <code>xxd</code> 将二进制文件转换为十六进制文本：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">xxd /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko &gt; kvm_hex.txt
</span></span></code></pre></div><p>这将创建一个名为 <code>kvm_hex.txt</code> 的文本文件，其中包含 <code>kvm.ko</code> 的十六进制表示。</p>
</li>
<li>
<p>使用文本编辑器（如 <code>nano</code> 或 <code>vim</code>）打开 <code>kvm_hex.txt</code>，找到并编辑 <code>module_layout</code> 的值。请确保你了解所做更改的含义，并且只修改你确信的内容。</p>
</li>
<li>
<p>保存并关闭文本编辑器。</p>
</li>
<li>
<p>使用 <code>xxd</code> 将修改后的十六进制文本转换回二进制文件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">xxd -r kvm_hex.txt &gt; /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko
</span></span></code></pre></div><p>这将覆盖原始的 <code>kvm.ko</code> 文件。</p>
</li>
</ol>
</li>
<li>
<p>方法二：修改 Module.symvers</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 清理编译结果。不要使用 make distclean，这会删除.config 文件以及 Module.symvers 文件</span>
</span></span><span class="line"><span class="cl">make clean
</span></span><span class="line"><span class="cl"><span class="c1"># 修改 Module.symvers 文件</span>
</span></span><span class="line"><span class="cl">sed -i  <span class="s1">&#39;/module_layout/ s/0x[0-9a-f][0-9a-f]*/0xdf88831e/&#39;</span> Module.symvers
</span></span><span class="line"><span class="cl"><span class="c1"># 重新编译模块</span>
</span></span><span class="line"><span class="cl">make <span class="nv">M</span><span class="o">=</span>./arch/riscv/kvm/ -j33
</span></span><span class="line"><span class="cl"><span class="c1"># 检查模块的 module_layout</span>
</span></span><span class="line"><span class="cl">modprobe --dump-modversions /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko <span class="p">|</span> grep module_layout
</span></span><span class="line"><span class="cl">0xdf88831e
</span></span></code></pre></div></li>
</ul>
<h1 id="如何生成-modc-文件">如何生成 .mod.c 文件</h1>
<p>如果是自己写的模块，可以根据下面的命令编译模块，就可以得到<code>.mod.c</code>文件，它是源文件到<code>.mod.o</code>文件的一个中间文件。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make -C /root/build-kernel/kernel <span class="nv">M</span><span class="o">=</span>/driver_study/ modules -j22
</span></span></code></pre></div><p>如果是用内核自己的模块，执行<code>make modules</code>命令，也可以得到<code>.mod.c</code>文件。但是一般执行<code>make -j22</code>命令就不会生成这些文件，我们可以找一个启用的内核模块，例如<code>kvm.ko</code>，执行下面的命令，就可以得到<code>.mod.c</code>文件。不能随便找个模块，必须在 config 中开启的模块，否则会报错<code>undefined!</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make  <span class="nv">M</span><span class="o">=</span>./arch/riscv/kvm modules -j22
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>uCore-实验第 0 章 - 实验环境搭建</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC0%E7%AB%A0-%E5%AE%9E%E9%AA%8C%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</link>
      <pubDate>Fri, 08 Sep 2023 10:46:20 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC0%E7%AB%A0-%E5%AE%9E%E9%AA%8C%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本次实验是清华大学操作系统课程的课程实验，实验内容是基于 RISC-V 架构的 uCore 操作系统。本次实验的目的是搭建实验环境，为后续实验做准备。指导书参考&lt;a href=&#34;https://learningos.github.io/uCore-Tutorial-Guide-2023S/index.html&#34;&gt;uCore-Tutorial-Guide-2023S 文档&lt;/a&gt;。本系列文章内容主要是指导书的补充以及我在实验过程的一些理解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本章没有什么需要特别说明的，指导手册十分详细，按照指导手册的步骤一步步来就可以了。因为平时也在用 WSL2 开发，所以配置十分顺利，没有遇到什么问题。这篇文章就当占坑了，如果后续有什么需要补充的再来更新。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<blockquote>
<p>本次实验是清华大学操作系统课程的课程实验，实验内容是基于 RISC-V 架构的 uCore 操作系统。本次实验的目的是搭建实验环境，为后续实验做准备。指导书参考<a href="https://learningos.github.io/uCore-Tutorial-Guide-2023S/index.html">uCore-Tutorial-Guide-2023S 文档</a>。本系列文章内容主要是指导书的补充以及我在实验过程的一些理解。</p>
</blockquote>
<p>本章没有什么需要特别说明的，指导手册十分详细，按照指导手册的步骤一步步来就可以了。因为平时也在用 WSL2 开发，所以配置十分顺利，没有遇到什么问题。这篇文章就当占坑了，如果后续有什么需要补充的再来更新。</p>
]]></content:encoded>
    </item>
    <item>
      <title>uCore-实验第 1 章 - 应用程序与基本执行环境</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC1%E7%AB%A0-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E4%B8%8E%E5%9F%BA%E6%9C%AC%E6%89%A7%E8%A1%8C%E7%8E%AF%E5%A2%83/</link>
      <pubDate>Fri, 08 Sep 2023 10:45:14 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC1%E7%AB%A0-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E4%B8%8E%E5%9F%BA%E6%9C%AC%E6%89%A7%E8%A1%8C%E7%8E%AF%E5%A2%83/</guid>
      <description>&lt;h1 id=&#34;了解系统调用&#34;&gt;了解系统调用&lt;/h1&gt;
&lt;p&gt;操作系统的系统调用（syscall）是操作系统提供给应用程序使用的一种接口。它允许应用程序通过向操作系统发送请求，来执行一些必须由操作系统来完成的任务，例如读取文件、创建进程、分配内存等。&lt;/p&gt;
&lt;p&gt;通俗地说，可以把操作系统看作一个巨大的服务员，而应用程序就像是顾客。应用程序不能直接访问硬件或执行特权操作，因为这样可能会导致系统不稳定或不安全。所以，应用程序需要通过系统调用来与操作系统进行交互，请求操作系统代表它完成某些任务。&lt;/p&gt;
&lt;p&gt;当应用程序需要操作系统执行特定的功能时，它会调用适当的系统调用函数，并传递参数给它。然后操作系统会接收到这个请求，并根据请求的类型和参数来执行相应的操作。完成后，操作系统会将执行结果返回给应用程序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在 RISC-V 架构中&lt;/strong&gt;，系统调用是通过使用特定的指令来实现的。具体来说，RISC-V 架构提供了一个称为 &lt;code&gt;ecall&lt;/code&gt;（environment call）的指令来触发系统调用。&lt;/p&gt;
&lt;p&gt;要使用 syscall，在 RISC-V 汇编代码中可以通过以下步骤来完成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将系统调用编号（syscall number）放入寄存器 a7 中，该编号对应于所需的系统调用功能。&lt;/li&gt;
&lt;li&gt;将系统调用所需的参数放入其他相应的寄存器中。例如，参数传递给文件读取系统调用可能需要将文件描述符放入 a0 寄存器，缓冲区地址放入 a1 寄存器，以及读取的字节数放入 a2 寄存器。&lt;/li&gt;
&lt;li&gt;执行 ecall 指令。这会触发操作系统处理当前运行的程序的系统调用请求。&lt;/li&gt;
&lt;li&gt;操作系统接收到系统调用请求后，根据寄存器 a7 中的系统调用编号和其他寄存器中的参数来执行相应的操作。&lt;/li&gt;
&lt;li&gt;当操作系统完成系统调用请求时，它将结果放入适当的寄存器中，通常是 a0 寄存器。&lt;/li&gt;
&lt;li&gt;程序继续执行，可以检查结果并进行后续的处理。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要注意的是，具体的系统调用编号以及参数的传递方式会根据操作系统的实现而有所不同。所以在编写 RISC-V 汇编代码时，需要参考操作系统的相关文档来了解具体的系统调用接口和参数传递方式。&lt;/p&gt;
&lt;h1 id=&#34;makr-run-之后发生了什么&#34;&gt;makr run 之后发生了什么？&lt;/h1&gt;
&lt;p&gt;当执行&lt;code&gt;make run&lt;/code&gt;命令后，以下是运行流程的概述：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;内核代码编译：执行&lt;code&gt;make run&lt;/code&gt;会触发 Makefile 中的相应规则，从而编译生成内核（kernel）二进制文件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;加载 kernel 并启动 QEMU：根据 QEMUOPTS 变量指定的参数，QEMU 加载生成的 kernel 二进制文件，并启动模拟器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;引导代码执行：在模拟器启动后，CPU 的通用寄存器被清零，程序计数器（PC）指向 0x1000 的位置，这里有硬件固化的一小段引导代码。该引导代码会迅速跳转到 0x80000000 处的 RustSBI（Rust Supervisor Binary Interface）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RustSBI 完成硬件初始化：RustSBI 是一个用于与操作系统进行交互的接口层。在跳转到 RustSBI 之后，它会完成必要的硬件初始化工作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行操作系统第一条指令：RustSBI 在完成硬件初始化后，会跳转到 kernel 二进制文件所在内存位置 0x80200000 处，并开始执行我们操作系统的第一条指令。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;综上所述，执行&lt;code&gt;make run&lt;/code&gt;命令会完成内核的编译和加载，启动 QEMU 虚拟机，并经过引导代码和 RustSBI 的处理，最终开始执行操作系统的第一条指令。&lt;/p&gt;
&lt;h1 id=&#34;了解链接脚本&#34;&gt;了解链接脚本&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# kernel.ld
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BASE_ADDRESS = 0x80200000;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SECTIONS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   . = BASE_ADDRESS;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   skernel = .;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   stext = .;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   .text : {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      *(.text.entry)   # 第一行代码
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      *(.text .text.*)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;kernelld-中的-base_address--0x80200000-指定了内核的加载地址这个地址哪来的&#34;&gt;kernel.ld 中的 &lt;code&gt;BASE_ADDRESS = 0x80200000&lt;/code&gt; 指定了内核的加载地址，这个地址哪来的？&lt;/h2&gt;
&lt;p&gt;以下内容摘自参考&lt;a href=&#34;https://rcore-os.cn/rCore-Tutorial-Book-v3/chapter1/3first-instruction-in-kernel1.html&#34;&gt;rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档&lt;/a&gt;：&lt;/p&gt;
&lt;p&gt;在 Qemu 模拟的 virt 硬件平台上，物理内存的起始物理地址为 &lt;code&gt;0x80000000&lt;/code&gt;，物理内存的默认大小为 128MiB，它可以通过 &lt;code&gt;-m&lt;/code&gt; 选项进行配置。如果使用默认配置的 128MiB 物理内存则对应的物理地址区间为 &lt;code&gt;[0x80000000,0x88000000)&lt;/code&gt; 。如果使用上面给出的命令启动 Qemu，那么在 Qemu 开始执行任何指令之前，首先把两个文件加载到 Qemu 的物理内存中：即作把作为 bootloader 的 rustsbi-qemu.bin 加载到物理内存以物理地址 &lt;code&gt;0x80000000&lt;/code&gt; 开头的区域上，同时把内核镜像 &lt;code&gt;os.bin&lt;/code&gt; 加载到以物理地址 &lt;code&gt;0x80200000&lt;/code&gt; 开头的区域上。&lt;/p&gt;
&lt;p&gt;为什么加载到这两个位置呢？这与 Qemu 模拟计算机加电启动后的运行流程有关。一般来说，计算机加电之后的启动流程可以分成若干个阶段，每个阶段均由一层软件或 固件 负责，每一层软件或固件的功能是进行它应当承担的初始化工作，并在此之后跳转到下一层软件或固件的入口地址，也就是将计算机的控制权移交给了下一层软件或固件。Qemu 模拟的启动流程则可以分为三个阶段：第一个阶段由固化在 Qemu 内的一小段汇编程序负责；第二个阶段由 bootloader 负责；第三个阶段则由内核镜像负责。&lt;/p&gt;
&lt;p&gt;第一阶段：将必要的文件载入到 Qemu 物理内存之后，Qemu CPU 的程序计数器（PC, Program Counter）会被初始化为 0x1000，因此 Qemu 实际执行的第一条指令位于物理地址 0x1000，接下来它将执行寥寥数条指令并跳转到物理地址 &lt;code&gt;0x80000000&lt;/code&gt; 对应的指令处并进入第二阶段。从后面的调试过程可以看出，该地址 &lt;code&gt;0x80000000&lt;/code&gt; 被固化在 Qemu 中，作为 Qemu 的使用者，我们在不触及 Qemu 源代码的情况下无法进行更改。&lt;/p&gt;
&lt;p&gt;第二阶段：由于 Qemu 的第一阶段固定跳转到 &lt;code&gt;0x80000000&lt;/code&gt;，我们需要将负责第二阶段的 bootloader rustsbi-qemu.bin 放在以物理地址 &lt;code&gt;0x80000000&lt;/code&gt; 开头的物理内存中，这样就能保证 &lt;code&gt;0x80000000&lt;/code&gt; 处正好保存 bootloader 的第一条指令。在这一阶段，bootloader 负责对计算机进行一些初始化工作，并跳转到下一阶段软件的入口，在 Qemu 上即可实现将计算机控制权移交给我们的内核镜像 os.bin。这里需要注意的是，对于不同的 bootloader 而言，下一阶段软件的入口不一定相同，而且获取这一信息的方式和时间点也不同：入口地址可能是一个预先约定好的固定的值，也有可能是在 bootloader 运行期间才动态获取到的值。我们选用的 RustSBI 则是将下一阶段的入口地址预先约定为固定的 0x80200000，在 RustSBI 的初始化工作完成之后，它会跳转到该地址并将计算机控制权移交给下一阶段的软件——也即我们的内核镜像。&lt;/p&gt;
&lt;p&gt;第三阶段：为了正确地和上一阶段的 RustSBI 对接，我们需要保证内核的第一条指令位于物理地址 &lt;code&gt;0x80200000&lt;/code&gt; 处。为此，我们需要将内核镜像预先加载到 Qemu 物理内存以地址 0x80200000 开头的区域上。一旦 CPU 开始执行内核的第一条指令，证明计算机的控制权已经被移交给我们的内核，也就达到了本节的目标。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以上过程是 QEMU 中的启动流程，真实计算机的加电启动流程大致如下：
第一阶段：加电后 CPU 的 PC 寄存器被设置为计算机内部只读存储器（ROM，Read-only Memory）的物理地址，随后 CPU 开始运行 ROM 内的软件。我们一般将该软件称为固件（Firmware），它的功能是对 CPU 进行一些初始化操作，将后续阶段的 bootloader 的代码、数据从硬盘载入到物理内存，最后跳转到适当的地址将计算机控制权转移给 bootloader。它大致对应于 Qemu 启动的第一阶段，即在物理地址 0x1000 处放置的若干条指令。可以看到 Qemu 上的固件非常简单，因为它并不需要负责将 bootloader 从硬盘加载到物理内存中，这个任务此前已经由 Qemu 自身完成了。
第二阶段：bootloader 同样完成一些 CPU 的初始化工作，将操作系统镜像从硬盘加载到物理内存中，最后跳转到适当地址将控制权转移给操作系统。可以看到一般情况下 bootloader 需要完成一些数据加载工作，这也就是它名字中 loader 的来源。它对应于 Qemu 启动的第二阶段。在 Qemu 中，我们使用的 RustSBI 功能较弱，它并没有能力完成加载的工作，内核镜像实际上是和 bootloader 一起在 Qemu 启动之前加载到物理内存中的。
第三阶段：控制权被转移给操作系统。由于篇幅所限后面我们就不再赘述了。
值得一提的是，为了让计算机的启动更加灵活，bootloader 目前可能非常复杂：它可能也分为多个阶段，并且能管理一些硬件资源，从复杂性上它已接近一个传统意义上的操作系统。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;终端是如何控制颜色的&#34;&gt;终端是如何控制颜色的？&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOG_COLOR&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;RED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;GREEN&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;BLUE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;34&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;GRAY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;90&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;YELLOW&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;93&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#if defined(USE_LOG_ERROR)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define errorf(fmt, ...)                                               \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	do {                                                               \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;		int tid = threadid();                                          \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;		printf(&amp;#34;\x1b[%dm[%s %d]&amp;#34; fmt &amp;#34;\x1b[0m\n&amp;#34;, RED, &amp;#34;ERROR&amp;#34;, tid,   \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;		       ##__VA_ARGS__);                                         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	} while (0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ANSI 转义码是一种用于控制终端输出的特殊字符序列。它们由&lt;code&gt;\x1b&lt;/code&gt;（或&lt;code&gt;\033&lt;/code&gt;）开头，后面跟着一系列数字和分号组成。&lt;/p&gt;
&lt;p&gt;ANSI 转义码中的数字部分用于指定不同的控制操作，如设置文本颜色、背景颜色、光标位置等等。其中，用于设置颜色的转义码包括三个主要的部分：&lt;code&gt;\x1b[颜色代码m&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;具体来说，&lt;code&gt;\x1b[&lt;/code&gt;表示开始使用控制序列，接下来的数字代表不同的颜色代码，最后的&lt;code&gt;m&lt;/code&gt;表示结束控制序列。例如，&lt;code&gt;\x1b[31m&lt;/code&gt;表示将文本颜色设置为红色，而&lt;code&gt;\x1b[0m&lt;/code&gt;用于重置所有属性为默认值。&lt;/p&gt;
&lt;p&gt;当终端遇到这样的转义序列时，它会解析并执行相应的控制操作，从而实现对文本颜色、背景颜色和其他属性的控制。&lt;/p&gt;
&lt;p&gt;需要注意的是，不同的终端可能支持不同的 ANSI 转义码，并且不同操作系统也可能有不同的实现。因此，在编写使用 ANSI 转义码的代码时，建议先测试并确保其在目标终端上正常工作。&lt;/p&gt;
&lt;p&gt;更多详细解释可以参考文章：&lt;a href=&#34;https://www.jianshu.com/p/790fc612aaa5&#34;&gt;终端颜色控制 - 简书&lt;/a&gt;。&lt;/p&gt;
&lt;h1 id=&#34;应用程序输出字符会调用-sbi-服务sbi-中发生了什么&#34;&gt;应用程序输出字符会调用 SBI 服务，SBI 中发生了什么？&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;因为对 Rust 语言不熟悉，所以这里的分析是基于 C 语言的 OpenSBI 来分析的，他们的逻辑是一样的。如果有熟悉 Rust 的可以查看 &lt;a href=&#34;https://github.com/rustsbi/rustsbi/blob/main/src/instance.rs&#34;&gt;RustSBI 源码&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据指导书中的解释以及阅读代码，我们知道调用了 &lt;code&gt;printf&lt;/code&gt; 最终实际上是调用了 &lt;code&gt;sbi_call&lt;/code&gt;。那么 &lt;code&gt;sbi_call&lt;/code&gt; 是如何实现的呢？因为我是做驱动开发以及固件开发的，也经常需要使用 OpenSBI，所想多问一句，OpenSBI 是如何实现的呢？OpenSBI 是如何提供服务的呢？它是如何打印出字符的呢？&lt;/p&gt;
&lt;h2 id=&#34;内核中的-sbi-调用&#34;&gt;内核中的 SBI 调用&lt;/h2&gt;
&lt;p&gt;我们先看一下内核中的 &lt;code&gt;sbi_call&lt;/code&gt; 都做了写啥。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// uCore-Tutorial-Code-2023S/os/sbi.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_CONSOLE_PUTCHAR&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;console_putchar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;sbi_call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SBI_CONSOLE_PUTCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// uCore-Tutorial-Code-2023S/os/sbi.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;inline&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;which&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 使用寄存器变量来保存参数值和系统调用编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;register&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;a0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 将 &amp;#39;arg0&amp;#39; 的值保存在寄存器 &amp;#39;a0&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;register&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a1&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;a1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 将 &amp;#39;arg1&amp;#39; 的值保存在寄存器 &amp;#39;a1&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;register&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a2&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;a2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 将 &amp;#39;arg2&amp;#39; 的值保存在寄存器 &amp;#39;a2&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;register&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a7&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;a7&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;which&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 &amp;#39;which&amp;#39; 的值保存在寄存器 &amp;#39;a7&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 内联汇编代码使用 ecall 指令进行系统调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;volatile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s&#34;&gt;&amp;#34;ecall&amp;#34;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 使用 ecall 指令进行系统调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 在这段代码中，指令 &amp;#34;ecall&amp;#34; 的输入参数是寄存器 a0 a1 a2 和 a7，输出参数是寄存器 a0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 输出操作数：将返回值存储在变量 &amp;#39;a0&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 输入操作数：传递参数和系统调用编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;memory&amp;#34;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;//  &amp;#34;memory&amp;#34; 标志告诉编译器，这条指令可能会修改内存中的数据，需要进行内存屏障操作来保证数据的正确性。 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 返回存储在变量 &amp;#39;a0&amp;#39; 中的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么 OpenSBI 如何提供服务？在&lt;code&gt;include/sbi/sbi_ecall.h&lt;/code&gt;这种定义了每个&lt;code&gt;ecall&lt;/code&gt;服务全局变量。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//include/sbi/sbi_ecall.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_base&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_legacy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_rfence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_ipi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_vendor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_hsm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_srst&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;lib/sbi/sbi_ecall.c&lt;/code&gt;中注册了所有的&lt;code&gt;ecall&lt;/code&gt;服务，并将其加到链表&lt;code&gt;ecall_exts_list&lt;/code&gt;中。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_exts_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_exts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_register_extension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_register_extension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EINVAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;sbi_list_for_each_entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ecall_exts_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;cm&#34;&gt;/* no overlap */&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EINVAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;SBI_INIT_LIST_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;sbi_list_add_tail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ecall_exts_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Iterate over list of given type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param pos the type * to use as a loop cursor.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param head the head for your list.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param member the name of the list_struct within the struct.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define sbi_list_for_each_entry(pos, head, member) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	for (pos = sbi_list_entry((head)-&amp;gt;next, typeof(*pos), member);	\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	     &amp;amp;pos-&amp;gt;member != (head); 	\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	     pos = sbi_list_entry(pos-&amp;gt;member.next, typeof(*pos), member))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么服务 id 如何和相对应的服务绑定的呢？以&lt;code&gt;ecall_time&lt;/code&gt;为例，查看其结构体原型&lt;code&gt;struct sbi_ecall_extension&lt;/code&gt; ：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// include/sbi/sbi_ecall.h: 23
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_dlist&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;probe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;funcid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		       &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		       &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		       &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到有 &lt;code&gt;extid_start&lt;/code&gt;、&lt;code&gt;extid_end&lt;/code&gt; 和 &lt;code&gt;handle&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;目前 OpenSBI 逐步将每个服务的实现都放在了&lt;code&gt;lib/sbi&lt;/code&gt;单独文件中，以&lt;code&gt;ecall_time&lt;/code&gt;为例，其实现在&lt;code&gt;lib/sbi/sbi_ecall_time.c&lt;/code&gt;中。单独为其绑定回调处理函数&lt;code&gt;sbi_ecall_time_handler&lt;/code&gt;。但是还有很多服务的实现还是放在了&lt;code&gt;lib/sbi/sbi_ecall_legacy.c&lt;/code&gt;中，后续应该会逐步迁移。我们上文使用的&lt;code&gt;SBI_CONSOLE_PUTCHAR&lt;/code&gt;服务就是在这里实现的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// lib/sbi/sbi_ecall_legacy.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_legacy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EXT_0_1_SET_TIMER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EXT_0_1_SHUTDOWN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_legacy_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_legacy_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;funcid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_tlb_info&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tlb_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;source_hart&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;current_hartid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;ulong&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SBI_EXT_0_1_SET_TIMER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;sbi_timer_event_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SBI_EXT_0_1_CONSOLE_PUTCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;sbi_putc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SBI_EXT_0_1_CONSOLE_GETCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_getc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这就把 &lt;code&gt;id&lt;/code&gt; 与相应的服务函数绑定。一个&lt;code&gt;extid&lt;/code&gt;对应一个&lt;code&gt;handler&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;我们可以在找到&lt;code&gt;SBI_EXT_0_1_CONSOLE_PUTCHAR&lt;/code&gt;的值，是与 Linux 内核里定义的值是一致的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// include/sbi/sbi_ecall_interface.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* SBI Extension IDs */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define SBI_EXT_0_1_CONSOLE_PUTCHAR		0x1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ecall-服务调用流程&#34;&gt;ecall 服务调用流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;firmware/fw_base.S&lt;/code&gt; 中注册了 &lt;code&gt;Machine Mode&lt;/code&gt; 的 &lt;code&gt;trap handler&lt;/code&gt;，即 &lt;code&gt;sbi_trap_handler&lt;/code&gt;；&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;_start_warm:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Setup trap handler */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;la&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;a4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;_trap_handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;csrw&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;CSR_MTVEC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a4&lt;/span&gt;  &lt;span class=&#34;cm&#34;&gt;/* CSR_MTVEC = _trap_handler */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;_trap_handler:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_SAVE_AND_SETUP_SP_T0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_SAVE_MEPC_MSTATUS&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_CALL_C_ROUTINE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_RESTORE_MEPC_MSTATUS&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_RESTORE_SP_T0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;mret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.macro&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;TRAP_CALL_C_ROUTINE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Call C routine */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;add&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;call&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;sbi_trap_handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.endm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;lib/sbi/sbi_trap.c&lt;/code&gt; 中定义了 &lt;code&gt;sbi_trap_handler&lt;/code&gt;，处理各种 &lt;code&gt;mcause&lt;/code&gt;，比如 &lt;code&gt;Illegal Instructions&lt;/code&gt;，&lt;code&gt;Misaligned Load &amp;amp; Store&lt;/code&gt;, &lt;code&gt;Supervisor &amp;amp; Machine Ecall&lt;/code&gt; 等。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// lib/sbi/sbi_trap.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_trap_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mcause&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_ILLEGAL_INSTRUCTION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_illegal_insn_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mtval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_MISALIGNED_LOAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_misaligned_load_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mtval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtval2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtinst&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_MISALIGNED_STORE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_misaligned_store_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mtval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtval2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtinst&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_SUPERVISOR_ECALL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_MACHINE_ECALL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* If the trap came from S or U mode, redirect it there */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;epc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mepc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cause&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mcause&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tval2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtval2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tinst&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtinst&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_trap_redirect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;lib/sbi/sbi_ecall.c&lt;/code&gt; 中定义了处理 &lt;code&gt;ecall mcause&lt;/code&gt; 的 &lt;code&gt;sbi_ecall_handler&lt;/code&gt;，它遍历上面 &lt;code&gt;ecall_exts_list&lt;/code&gt; 中注册的各种 &lt;code&gt;ecall&lt;/code&gt; 服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;sbi_ecall_handler&lt;/code&gt; 根据 Linux 内核传递的 &lt;code&gt;ext (extension id)&lt;/code&gt; 找到链表中对应的 &lt;code&gt;ecall&lt;/code&gt; 服务，执行其中的 &lt;code&gt;handle&lt;/code&gt; 函数，该函数根据 &lt;code&gt;fid&lt;/code&gt; 执行具体的服务内容。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// lib/sbi/sbi_ecall.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;func_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_info&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 遍历所有 ecall 服务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_find_extension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 如果找到了就执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;func_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EXT_0_1_SET_TIMER&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EXT_0_1_SHUTDOWN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;is_0_1_spec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_ENOTSUPP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以发现 &lt;code&gt;extension_id&lt;/code&gt; 就是 a7 寄存器，他和我们在 uCore OS 中定义的 &lt;code&gt;SBI_EXT_0_1_CONSOLE_PUTCHAR&lt;/code&gt; 是一致的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;程序的内存布局与编译流程&#34;&gt;程序的内存布局与编译流程&lt;/h1&gt;
&lt;h2 id=&#34;程序的内存布局&#34;&gt;程序的内存布局&lt;/h2&gt;
&lt;h1 id=&#34;ucore-的编译系统&#34;&gt;uCore 的编译系统&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;.PHONY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clean&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 设置伪目标clean、build和user，可以通过命令make来执行这些目标
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build_kernel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 默认目标为build_kernel，即执行build_kernel目标下的指令
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?=&lt;/span&gt; error
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量LOG，默认值是error
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;K&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; os
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;TOOLPREFIX&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; riscv64-unknown-elf-
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;gcc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;AS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;gcc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LD&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;ld
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;OBJCOPY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;objcopy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;OBJDUMP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;objdump
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;GDB&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;gdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; cp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MKDIR_P&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; mkdir -p
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;C_SRCS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;wildcard &lt;span class=&#34;nv&#34;&gt;$K&lt;/span&gt;/*.c&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量C_SRCS，使用wildcard函数匹配所有以.c为后缀的文件，并存储在$K目录下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;AS_SRCS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;wildcard &lt;span class=&#34;nv&#34;&gt;$K&lt;/span&gt;/*.S&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量AS_SRCS，使用wildcard函数匹配所有以.S为后缀的文件，并存储在$K目录下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;C_OBJS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addprefix &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addsuffix .o, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;basename &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;C_SRCS&lt;span class=&#34;k&#34;&gt;))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量C_OBJS，通过addprefix和addsuffix函数将$(C_SRCS)中的路径替换为$(BUILDDIR)，并将后缀修改为.o
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;AS_OBJS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addprefix &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addsuffix .o, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;basename &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;AS_SRCS&lt;span class=&#34;k&#34;&gt;))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量AS_OBJS，通过addprefix和addsuffix函数将$(AS_SRCS)中的路径替换为$(BUILDDIR)，并将后缀修改为.o
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;OBJS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;C_OBJS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;AS_OBJS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量OBJS，其值为$(C_OBJS)和$(AS_OBJS)的组合
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;HEADER_DEP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addsuffix .d, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;basename &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;C_OBJS&lt;span class=&#34;k&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量HEADER_DEP，通过addsuffix函数将$(C_OBJS)中的后缀修改为.d
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;-include&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;HEADER_DEP&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 包含$(HEADER_DEP)中的.d文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; -Wall -Werror -O -fno-omit-frame-pointer -ggdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量CFLAGS，并赋值为-Wall -Werror -O -fno-omit-frame-pointer -ggdb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -MD
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将-MD选项追加到CFLAGS变量中，用于自动生成依赖关系文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -mcmodel&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;medany
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将-mcmodel=medany选项追加到CFLAGS变量中，用于指定内存模型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -ffreestanding -fno-common -nostdlib -mno-relax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将-ffreestanding -fno-common -nostdlib -mno-relax选项追加到CFLAGS变量中，用于编译无操作系统环境下的程序
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -I&lt;span class=&#34;nv&#34;&gt;$K&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将-I$K选项追加到CFLAGS变量中，用于指定头文件搜索路径为$K目录下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;shell &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -fno-stack-protector -E -x c /dev/null &amp;gt;/dev/null 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -fno-stack-protector&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将$(CC) -fno-stack-protector -E -x c /dev/null &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&amp;amp; echo -fno-stack-protector命令执行结果追加到CFLAGS变量中，用于禁用栈保护机制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;error)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;warn)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_WARN
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;info)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_INFO
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;debug)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_DEBUG
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;trace)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_TRACE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 根据$(LOG)变量的值，向CFLAGS变量追加相应的预处理器选项，相当于添加了一个宏定义，log.h中的LOG_LEVEL_ERROR等宏定义会根据这个宏定义来决定是否生效
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Disable PIE when possible (for Ubuntu 16.10 toolchain)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;ifneq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;shell&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;CC&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -&lt;span class=&#34;nv&#34;&gt;dumpspecs&lt;/span&gt; 2&amp;gt;/&lt;span class=&#34;nv&#34;&gt;dev&lt;/span&gt;/&lt;span class=&#34;nv&#34;&gt;null&lt;/span&gt; | &lt;span class=&#34;nv&#34;&gt;grep&lt;/span&gt; -&lt;span class=&#34;nv&#34;&gt;e&lt;/span&gt; &amp;#39;[^&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;]&lt;span class=&#34;nv&#34;&gt;no&lt;/span&gt;-&lt;span class=&#34;nv&#34;&gt;pie&lt;/span&gt;&amp;#39;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -fno-pie -no-pie
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;ifneq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;shell&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;CC&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -&lt;span class=&#34;nv&#34;&gt;dumpspecs&lt;/span&gt; 2&amp;gt;/&lt;span class=&#34;nv&#34;&gt;dev&lt;/span&gt;/&lt;span class=&#34;nv&#34;&gt;null&lt;/span&gt; | &lt;span class=&#34;nv&#34;&gt;grep&lt;/span&gt; -&lt;span class=&#34;nv&#34;&gt;e&lt;/span&gt; &amp;#39;[^&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;]&lt;span class=&#34;nv&#34;&gt;nopie&lt;/span&gt;&amp;#39;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -fno-pie -nopie
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 根据系统环境判断是否支持PIE（位置无关执行）选项，并根据情况向CFLAGS变量追加相应的选项
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LDFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; -z max-page-size&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4096&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量LDFLAGS，并赋值为-z max-page-size=4096
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;$(AS_OBJS)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/$&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; : $&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @mkdir -p &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;@D&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -c $&amp;lt; -o &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 规则：生成$(AS_OBJS)目标所需的依赖文件$(BUILDDIR)/$K/%.o，依赖于$K/%.S，并通过$(CC)命令编译生成目标文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;$(C_OBJS)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/$&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; : $&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/$&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @mkdir -p &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;@D&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -c $&amp;lt; -o &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 规则：生成$(C_OBJS)目标所需的依赖文件$(BUILDDIR)/$K/%.o，依赖于$K/%.c和$(BUILDDIR)/$K/%.d，并通过$(CC)命令编译生成目标文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;$(HEADER_DEP)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/$&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;d&lt;/span&gt; : $&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @mkdir -p &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;@D&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @set -e&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; rm -f &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -MM $&amp;lt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;INCLUDEFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &amp;gt; &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;.&lt;span class=&#34;nv&#34;&gt;$$$$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;s,\($*\)\.o[ :]*,\1.o $@ : ,g&amp;#39;&lt;/span&gt; &amp;lt; &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;.&lt;span class=&#34;nv&#34;&gt;$$$$&lt;/span&gt; &amp;gt; &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        rm -f &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;.&lt;span class=&#34;nv&#34;&gt;$$$$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 规则：生成$(HEADER_DEP)目标所需的依赖文件$(BUILDDIR)/$K/%.d，依赖于$K/%.c，并通过$(CC)命令生成依赖关系文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;/&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个目标build，其依赖于build/kernel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;build/kernel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;OBJS&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;LD&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;LDFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -T os/kernel.ld -o &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;OBJS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;OBJDUMP&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -S &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel &amp;gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel.asm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;OBJDUMP&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -t &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d&amp;#39;&lt;/span&gt; &amp;gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel.sym
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @echo &lt;span class=&#34;s1&#34;&gt;&amp;#39;Build kernel done&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 规则：生成build/kernel目标，依赖于$(OBJS)，通过$(LD)命令连接生成kernel，并通过$(OBJDUMP)命令生成汇编文件和符号表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;clean&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    rm -rf &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# BOARD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;BOARD&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;?=&lt;/span&gt; qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SBI&lt;/span&gt;			&lt;span class=&#34;o&#34;&gt;?=&lt;/span&gt; rustsbi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;BOOTLOADER&lt;/span&gt;	&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; ./bootloader/rustsbi-qemu.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;QEMU&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; qemu-system-riscv64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;QEMUOPTS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	-nographic &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	-machine virt &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	-bios &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BOOTLOADER&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	-kernel build/kernel	&lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;/&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMU&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMUOPTS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# QEMU&amp;#39;s gdb stub command line changed in 0.11
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;QEMUGDB&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;shell &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMU&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -help &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep -q &lt;span class=&#34;s1&#34;&gt;&amp;#39;^-gdb&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;then&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-gdb tcp::15234&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-s -p 15234&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 启动QEMU并通过GDB调试，此时QEMu会进入后台运行，并暂停执行，等待GDB连接
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 连接的GDB端口为15234
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;debug&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;/&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt; .&lt;span class=&#34;n&#34;&gt;gdbinit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMU&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMUOPTS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -S &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMUGDB&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	sleep &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;GDB&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译、运行 uCore 的一些常用命令有如下一些，涉及了后续章节中引入的测试用例中的命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make run
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make debug
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 编译测试用例的前四章&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make user &lt;span class=&#34;nv&#34;&gt;CHAPTER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 编译测试用例的第四章&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make user &lt;span class=&#34;nv&#34;&gt;CHAPTER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4_only &lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 只运行测试用例的第四章&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;CHAPTER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4_only    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;附录&#34;&gt;附录&lt;/h1&gt;
&lt;p&gt;makefile 和 qemu&lt;/p&gt;
&lt;p&gt;AS = $(TOOLPREFIX)gas  &amp;gt; AS = $(TOOLPREFIX)as&lt;/p&gt;
&lt;h1 id=&#34;参考资料&#34;&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.jianshu.com/p/790fc612aaa5&#34;&gt;终端颜色控制 - 简书&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<h1 id="了解系统调用">了解系统调用</h1>
<p>操作系统的系统调用（syscall）是操作系统提供给应用程序使用的一种接口。它允许应用程序通过向操作系统发送请求，来执行一些必须由操作系统来完成的任务，例如读取文件、创建进程、分配内存等。</p>
<p>通俗地说，可以把操作系统看作一个巨大的服务员，而应用程序就像是顾客。应用程序不能直接访问硬件或执行特权操作，因为这样可能会导致系统不稳定或不安全。所以，应用程序需要通过系统调用来与操作系统进行交互，请求操作系统代表它完成某些任务。</p>
<p>当应用程序需要操作系统执行特定的功能时，它会调用适当的系统调用函数，并传递参数给它。然后操作系统会接收到这个请求，并根据请求的类型和参数来执行相应的操作。完成后，操作系统会将执行结果返回给应用程序。</p>
<p><strong>在 RISC-V 架构中</strong>，系统调用是通过使用特定的指令来实现的。具体来说，RISC-V 架构提供了一个称为 <code>ecall</code>（environment call）的指令来触发系统调用。</p>
<p>要使用 syscall，在 RISC-V 汇编代码中可以通过以下步骤来完成：</p>
<ol>
<li>将系统调用编号（syscall number）放入寄存器 a7 中，该编号对应于所需的系统调用功能。</li>
<li>将系统调用所需的参数放入其他相应的寄存器中。例如，参数传递给文件读取系统调用可能需要将文件描述符放入 a0 寄存器，缓冲区地址放入 a1 寄存器，以及读取的字节数放入 a2 寄存器。</li>
<li>执行 ecall 指令。这会触发操作系统处理当前运行的程序的系统调用请求。</li>
<li>操作系统接收到系统调用请求后，根据寄存器 a7 中的系统调用编号和其他寄存器中的参数来执行相应的操作。</li>
<li>当操作系统完成系统调用请求时，它将结果放入适当的寄存器中，通常是 a0 寄存器。</li>
<li>程序继续执行，可以检查结果并进行后续的处理。</li>
</ol>
<p>需要注意的是，具体的系统调用编号以及参数的传递方式会根据操作系统的实现而有所不同。所以在编写 RISC-V 汇编代码时，需要参考操作系统的相关文档来了解具体的系统调用接口和参数传递方式。</p>
<h1 id="makr-run-之后发生了什么">makr run 之后发生了什么？</h1>
<p>当执行<code>make run</code>命令后，以下是运行流程的概述：</p>
<ol>
<li>
<p>内核代码编译：执行<code>make run</code>会触发 Makefile 中的相应规则，从而编译生成内核（kernel）二进制文件。</p>
</li>
<li>
<p>加载 kernel 并启动 QEMU：根据 QEMUOPTS 变量指定的参数，QEMU 加载生成的 kernel 二进制文件，并启动模拟器。</p>
</li>
<li>
<p>引导代码执行：在模拟器启动后，CPU 的通用寄存器被清零，程序计数器（PC）指向 0x1000 的位置，这里有硬件固化的一小段引导代码。该引导代码会迅速跳转到 0x80000000 处的 RustSBI（Rust Supervisor Binary Interface）。</p>
</li>
<li>
<p>RustSBI 完成硬件初始化：RustSBI 是一个用于与操作系统进行交互的接口层。在跳转到 RustSBI 之后，它会完成必要的硬件初始化工作。</p>
</li>
<li>
<p>执行操作系统第一条指令：RustSBI 在完成硬件初始化后，会跳转到 kernel 二进制文件所在内存位置 0x80200000 处，并开始执行我们操作系统的第一条指令。</p>
</li>
</ol>
<p>综上所述，执行<code>make run</code>命令会完成内核的编译和加载，启动 QEMU 虚拟机，并经过引导代码和 RustSBI 的处理，最终开始执行操作系统的第一条指令。</p>
<h1 id="了解链接脚本">了解链接脚本</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># kernel.ld
</span></span><span class="line"><span class="cl">BASE_ADDRESS = 0x80200000;
</span></span><span class="line"><span class="cl">SECTIONS
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">   . = BASE_ADDRESS;
</span></span><span class="line"><span class="cl">   skernel = .;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   stext = .;
</span></span><span class="line"><span class="cl">   .text : {
</span></span><span class="line"><span class="cl">      *(.text.entry)   # 第一行代码
</span></span><span class="line"><span class="cl">      *(.text .text.*)
</span></span><span class="line"><span class="cl">   }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   ...
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><h2 id="kernelld-中的-base_address--0x80200000-指定了内核的加载地址这个地址哪来的">kernel.ld 中的 <code>BASE_ADDRESS = 0x80200000</code> 指定了内核的加载地址，这个地址哪来的？</h2>
<p>以下内容摘自参考<a href="https://rcore-os.cn/rCore-Tutorial-Book-v3/chapter1/3first-instruction-in-kernel1.html">rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档</a>：</p>
<p>在 Qemu 模拟的 virt 硬件平台上，物理内存的起始物理地址为 <code>0x80000000</code>，物理内存的默认大小为 128MiB，它可以通过 <code>-m</code> 选项进行配置。如果使用默认配置的 128MiB 物理内存则对应的物理地址区间为 <code>[0x80000000,0x88000000)</code> 。如果使用上面给出的命令启动 Qemu，那么在 Qemu 开始执行任何指令之前，首先把两个文件加载到 Qemu 的物理内存中：即作把作为 bootloader 的 rustsbi-qemu.bin 加载到物理内存以物理地址 <code>0x80000000</code> 开头的区域上，同时把内核镜像 <code>os.bin</code> 加载到以物理地址 <code>0x80200000</code> 开头的区域上。</p>
<p>为什么加载到这两个位置呢？这与 Qemu 模拟计算机加电启动后的运行流程有关。一般来说，计算机加电之后的启动流程可以分成若干个阶段，每个阶段均由一层软件或 固件 负责，每一层软件或固件的功能是进行它应当承担的初始化工作，并在此之后跳转到下一层软件或固件的入口地址，也就是将计算机的控制权移交给了下一层软件或固件。Qemu 模拟的启动流程则可以分为三个阶段：第一个阶段由固化在 Qemu 内的一小段汇编程序负责；第二个阶段由 bootloader 负责；第三个阶段则由内核镜像负责。</p>
<p>第一阶段：将必要的文件载入到 Qemu 物理内存之后，Qemu CPU 的程序计数器（PC, Program Counter）会被初始化为 0x1000，因此 Qemu 实际执行的第一条指令位于物理地址 0x1000，接下来它将执行寥寥数条指令并跳转到物理地址 <code>0x80000000</code> 对应的指令处并进入第二阶段。从后面的调试过程可以看出，该地址 <code>0x80000000</code> 被固化在 Qemu 中，作为 Qemu 的使用者，我们在不触及 Qemu 源代码的情况下无法进行更改。</p>
<p>第二阶段：由于 Qemu 的第一阶段固定跳转到 <code>0x80000000</code>，我们需要将负责第二阶段的 bootloader rustsbi-qemu.bin 放在以物理地址 <code>0x80000000</code> 开头的物理内存中，这样就能保证 <code>0x80000000</code> 处正好保存 bootloader 的第一条指令。在这一阶段，bootloader 负责对计算机进行一些初始化工作，并跳转到下一阶段软件的入口，在 Qemu 上即可实现将计算机控制权移交给我们的内核镜像 os.bin。这里需要注意的是，对于不同的 bootloader 而言，下一阶段软件的入口不一定相同，而且获取这一信息的方式和时间点也不同：入口地址可能是一个预先约定好的固定的值，也有可能是在 bootloader 运行期间才动态获取到的值。我们选用的 RustSBI 则是将下一阶段的入口地址预先约定为固定的 0x80200000，在 RustSBI 的初始化工作完成之后，它会跳转到该地址并将计算机控制权移交给下一阶段的软件——也即我们的内核镜像。</p>
<p>第三阶段：为了正确地和上一阶段的 RustSBI 对接，我们需要保证内核的第一条指令位于物理地址 <code>0x80200000</code> 处。为此，我们需要将内核镜像预先加载到 Qemu 物理内存以地址 0x80200000 开头的区域上。一旦 CPU 开始执行内核的第一条指令，证明计算机的控制权已经被移交给我们的内核，也就达到了本节的目标。</p>
<blockquote>
<p>以上过程是 QEMU 中的启动流程，真实计算机的加电启动流程大致如下：
第一阶段：加电后 CPU 的 PC 寄存器被设置为计算机内部只读存储器（ROM，Read-only Memory）的物理地址，随后 CPU 开始运行 ROM 内的软件。我们一般将该软件称为固件（Firmware），它的功能是对 CPU 进行一些初始化操作，将后续阶段的 bootloader 的代码、数据从硬盘载入到物理内存，最后跳转到适当的地址将计算机控制权转移给 bootloader。它大致对应于 Qemu 启动的第一阶段，即在物理地址 0x1000 处放置的若干条指令。可以看到 Qemu 上的固件非常简单，因为它并不需要负责将 bootloader 从硬盘加载到物理内存中，这个任务此前已经由 Qemu 自身完成了。
第二阶段：bootloader 同样完成一些 CPU 的初始化工作，将操作系统镜像从硬盘加载到物理内存中，最后跳转到适当地址将控制权转移给操作系统。可以看到一般情况下 bootloader 需要完成一些数据加载工作，这也就是它名字中 loader 的来源。它对应于 Qemu 启动的第二阶段。在 Qemu 中，我们使用的 RustSBI 功能较弱，它并没有能力完成加载的工作，内核镜像实际上是和 bootloader 一起在 Qemu 启动之前加载到物理内存中的。
第三阶段：控制权被转移给操作系统。由于篇幅所限后面我们就不再赘述了。
值得一提的是，为了让计算机的启动更加灵活，bootloader 目前可能非常复杂：它可能也分为多个阶段，并且能管理一些硬件资源，从复杂性上它已接近一个传统意义上的操作系统。</p>
</blockquote>
<h1 id="终端是如何控制颜色的">终端是如何控制颜色的？</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">enum</span> <span class="n">LOG_COLOR</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">RED</span> <span class="o">=</span> <span class="mi">31</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">GREEN</span> <span class="o">=</span> <span class="mi">32</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">BLUE</span> <span class="o">=</span> <span class="mi">34</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">GRAY</span> <span class="o">=</span> <span class="mi">90</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">YELLOW</span> <span class="o">=</span> <span class="mi">93</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#if defined(USE_LOG_ERROR)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define errorf(fmt, ...)                                               \
</span></span></span><span class="line"><span class="cl"><span class="cp">	do {                                                               \
</span></span></span><span class="line"><span class="cl"><span class="cp">		int tid = threadid();                                          \
</span></span></span><span class="line"><span class="cl"><span class="cp">		printf(&#34;\x1b[%dm[%s %d]&#34; fmt &#34;\x1b[0m\n&#34;, RED, &#34;ERROR&#34;, tid,   \
</span></span></span><span class="line"><span class="cl"><span class="cp">		       ##__VA_ARGS__);                                         \
</span></span></span><span class="line"><span class="cl"><span class="cp">	} while (0)
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span></code></pre></div><p>ANSI 转义码是一种用于控制终端输出的特殊字符序列。它们由<code>\x1b</code>（或<code>\033</code>）开头，后面跟着一系列数字和分号组成。</p>
<p>ANSI 转义码中的数字部分用于指定不同的控制操作，如设置文本颜色、背景颜色、光标位置等等。其中，用于设置颜色的转义码包括三个主要的部分：<code>\x1b[颜色代码m</code>。</p>
<p>具体来说，<code>\x1b[</code>表示开始使用控制序列，接下来的数字代表不同的颜色代码，最后的<code>m</code>表示结束控制序列。例如，<code>\x1b[31m</code>表示将文本颜色设置为红色，而<code>\x1b[0m</code>用于重置所有属性为默认值。</p>
<p>当终端遇到这样的转义序列时，它会解析并执行相应的控制操作，从而实现对文本颜色、背景颜色和其他属性的控制。</p>
<p>需要注意的是，不同的终端可能支持不同的 ANSI 转义码，并且不同操作系统也可能有不同的实现。因此，在编写使用 ANSI 转义码的代码时，建议先测试并确保其在目标终端上正常工作。</p>
<p>更多详细解释可以参考文章：<a href="https://www.jianshu.com/p/790fc612aaa5">终端颜色控制 - 简书</a>。</p>
<h1 id="应用程序输出字符会调用-sbi-服务sbi-中发生了什么">应用程序输出字符会调用 SBI 服务，SBI 中发生了什么？</h1>
<blockquote>
<p>因为对 Rust 语言不熟悉，所以这里的分析是基于 C 语言的 OpenSBI 来分析的，他们的逻辑是一样的。如果有熟悉 Rust 的可以查看 <a href="https://github.com/rustsbi/rustsbi/blob/main/src/instance.rs">RustSBI 源码</a></p>
</blockquote>
<p>根据指导书中的解释以及阅读代码，我们知道调用了 <code>printf</code> 最终实际上是调用了 <code>sbi_call</code>。那么 <code>sbi_call</code> 是如何实现的呢？因为我是做驱动开发以及固件开发的，也经常需要使用 OpenSBI，所想多问一句，OpenSBI 是如何实现的呢？OpenSBI 是如何提供服务的呢？它是如何打印出字符的呢？</p>
<h2 id="内核中的-sbi-调用">内核中的 SBI 调用</h2>
<p>我们先看一下内核中的 <code>sbi_call</code> 都做了写啥。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// uCore-Tutorial-Code-2023S/os/sbi.c
</span></span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="n">uint64</span> <span class="n">SBI_CONSOLE_PUTCHAR</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">console_putchar</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nf">sbi_call</span><span class="p">(</span><span class="n">SBI_CONSOLE_PUTCHAR</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// uCore-Tutorial-Code-2023S/os/sbi.c
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="kr">inline</span> <span class="nf">sbi_call</span><span class="p">(</span><span class="n">uint64</span> <span class="n">which</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">arg0</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">arg1</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">arg2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 使用寄存器变量来保存参数值和系统调用编号
</span></span></span><span class="line"><span class="cl">    <span class="k">register</span> <span class="n">uint64</span> <span class="n">a0</span> <span class="k">asm</span><span class="p">(</span><span class="s">&#34;a0&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">arg0</span><span class="p">;</span>  <span class="c1">// 将 &#39;arg0&#39; 的值保存在寄存器 &#39;a0&#39; 中
</span></span></span><span class="line"><span class="cl">    <span class="k">register</span> <span class="n">uint64</span> <span class="n">a1</span> <span class="k">asm</span><span class="p">(</span><span class="s">&#34;a1&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">arg1</span><span class="p">;</span>  <span class="c1">// 将 &#39;arg1&#39; 的值保存在寄存器 &#39;a1&#39; 中
</span></span></span><span class="line"><span class="cl">    <span class="k">register</span> <span class="n">uint64</span> <span class="n">a2</span> <span class="k">asm</span><span class="p">(</span><span class="s">&#34;a2&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">arg2</span><span class="p">;</span>  <span class="c1">// 将 &#39;arg2&#39; 的值保存在寄存器 &#39;a2&#39; 中
</span></span></span><span class="line"><span class="cl">    <span class="k">register</span> <span class="n">uint64</span> <span class="n">a7</span> <span class="k">asm</span><span class="p">(</span><span class="s">&#34;a7&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">which</span><span class="p">;</span> <span class="c1">// 将 &#39;which&#39; 的值保存在寄存器 &#39;a7&#39; 中
</span></span></span><span class="line"><span class="cl">    <span class="c1">// 内联汇编代码使用 ecall 指令进行系统调用
</span></span></span><span class="line"><span class="cl">    <span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;ecall&#34;</span>  <span class="c1">// 使用 ecall 指令进行系统调用
</span></span></span><span class="line"><span class="cl">        <span class="c1">// 在这段代码中，指令 &#34;ecall&#34; 的输入参数是寄存器 a0 a1 a2 和 a7，输出参数是寄存器 a0
</span></span></span><span class="line"><span class="cl">        <span class="o">:</span> <span class="s">&#34;=r&#34;</span><span class="p">(</span><span class="n">a0</span><span class="p">)</span>  <span class="c1">// 输出操作数：将返回值存储在变量 &#39;a0&#39; 中
</span></span></span><span class="line"><span class="cl">        <span class="o">:</span> <span class="s">&#34;r&#34;</span><span class="p">(</span><span class="n">a0</span><span class="p">),</span> <span class="s">&#34;r&#34;</span><span class="p">(</span><span class="n">a1</span><span class="p">),</span> <span class="s">&#34;r&#34;</span><span class="p">(</span><span class="n">a2</span><span class="p">),</span> <span class="s">&#34;r&#34;</span><span class="p">(</span><span class="n">a7</span><span class="p">)</span>  <span class="c1">// 输入操作数：传递参数和系统调用编号
</span></span></span><span class="line"><span class="cl">        <span class="o">:</span> <span class="s">&#34;memory&#34;</span>  <span class="c1">//  &#34;memory&#34; 标志告诉编译器，这条指令可能会修改内存中的数据，需要进行内存屏障操作来保证数据的正确性。 
</span></span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a0</span><span class="p">;</span>  <span class="c1">// 返回存储在变量 &#39;a0&#39; 中的值
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>那么 OpenSBI 如何提供服务？在<code>include/sbi/sbi_ecall.h</code>这种定义了每个<code>ecall</code>服务全局变量。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//include/sbi/sbi_ecall.h
</span></span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_base</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_legacy</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_time</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_rfence</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_ipi</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_vendor</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_hsm</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_srst</span><span class="p">;</span>
</span></span></code></pre></div><p>在<code>lib/sbi/sbi_ecall.c</code>中注册了所有的<code>ecall</code>服务，并将其加到链表<code>ecall_exts_list</code>中。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">sbi_ecall_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">ret</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="o">*</span><span class="n">ext</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">sbi_ecall_exts_size</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">ext</span> <span class="o">=</span> <span class="n">sbi_ecall_exts</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">		<span class="n">ret</span> <span class="o">=</span> <span class="nf">sbi_ecall_register_extension</span><span class="p">(</span><span class="n">ext</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">sbi_ecall_register_extension</span><span class="p">(</span><span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="o">*</span><span class="n">ext</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="o">*</span><span class="n">t</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ext</span> <span class="o">||</span> <span class="p">(</span><span class="n">ext</span><span class="o">-&gt;</span><span class="n">extid_end</span> <span class="o">&lt;</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="n">extid_start</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span><span class="n">ext</span><span class="o">-&gt;</span><span class="n">handle</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="n">SBI_EINVAL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nf">sbi_list_for_each_entry</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ecall_exts_list</span><span class="p">,</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">start</span> <span class="o">=</span> <span class="n">t</span><span class="o">-&gt;</span><span class="n">extid_start</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">end</span> <span class="o">=</span> <span class="n">t</span><span class="o">-&gt;</span><span class="n">extid_end</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="p">(</span><span class="n">end</span> <span class="o">&lt;</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="n">extid_start</span> <span class="o">||</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="n">extid_end</span> <span class="o">&lt;</span> <span class="n">start</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="cm">/* no overlap */</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">else</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="n">SBI_EINVAL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nf">SBI_INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ext</span><span class="o">-&gt;</span><span class="n">head</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nf">sbi_list_add_tail</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ext</span><span class="o">-&gt;</span><span class="n">head</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ecall_exts_list</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Iterate over list of given type
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param pos the type * to use as a loop cursor.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param head the head for your list.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param member the name of the list_struct within the struct.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define sbi_list_for_each_entry(pos, head, member) \
</span></span></span><span class="line"><span class="cl"><span class="cp">	for (pos = sbi_list_entry((head)-&gt;next, typeof(*pos), member);	\
</span></span></span><span class="line"><span class="cl"><span class="cp">	     &amp;pos-&gt;member != (head); 	\
</span></span></span><span class="line"><span class="cl"><span class="cp">	     pos = sbi_list_entry(pos-&gt;member.next, typeof(*pos), member))
</span></span></span></code></pre></div><p>那么服务 id 如何和相对应的服务绑定的呢？以<code>ecall_time</code>为例，查看其结构体原型<code>struct sbi_ecall_extension</code> ：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// include/sbi/sbi_ecall.h: 23
</span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">struct</span> <span class="n">sbi_dlist</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid_start</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid_end</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="p">(</span><span class="o">*</span> <span class="n">probe</span><span class="p">)(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">out_val</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="p">(</span><span class="o">*</span> <span class="n">handle</span><span class="p">)(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">funcid</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		       <span class="k">const</span> <span class="k">struct</span> <span class="n">sbi_trap_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		       <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">out_val</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		       <span class="k">struct</span> <span class="n">sbi_trap_info</span> <span class="o">*</span><span class="n">out_trap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>可以看到有 <code>extid_start</code>、<code>extid_end</code> 和 <code>handle</code>。</p>
<p>目前 OpenSBI 逐步将每个服务的实现都放在了<code>lib/sbi</code>单独文件中，以<code>ecall_time</code>为例，其实现在<code>lib/sbi/sbi_ecall_time.c</code>中。单独为其绑定回调处理函数<code>sbi_ecall_time_handler</code>。但是还有很多服务的实现还是放在了<code>lib/sbi/sbi_ecall_legacy.c</code>中，后续应该会逐步迁移。我们上文使用的<code>SBI_CONSOLE_PUTCHAR</code>服务就是在这里实现的。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// lib/sbi/sbi_ecall_legacy.c
</span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_legacy</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="n">extid_start</span> <span class="o">=</span> <span class="n">SBI_EXT_0_1_SET_TIMER</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="n">extid_end</span> <span class="o">=</span> <span class="n">SBI_EXT_0_1_SHUTDOWN</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="n">handle</span> <span class="o">=</span> <span class="n">sbi_ecall_legacy_handler</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">sbi_ecall_legacy_handler</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">funcid</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				    <span class="k">const</span> <span class="k">struct</span> <span class="n">sbi_trap_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">out_val</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				    <span class="k">struct</span> <span class="n">sbi_trap_info</span> <span class="o">*</span><span class="n">out_trap</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">struct</span> <span class="n">sbi_tlb_info</span> <span class="n">tlb_info</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="n">u32</span> <span class="n">source_hart</span> <span class="o">=</span> <span class="nf">current_hartid</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="n">ulong</span> <span class="n">hmask</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">switch</span> <span class="p">(</span><span class="n">extid</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nl">SBI_EXT_0_1_SET_TIMER</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="nf">sbi_timer_event_start</span><span class="p">((</span><span class="n">u64</span><span class="p">)</span><span class="n">regs</span><span class="o">-&gt;</span><span class="n">a0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nl">SBI_EXT_0_1_CONSOLE_PUTCHAR</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="nf">sbi_putc</span><span class="p">(</span><span class="n">regs</span><span class="o">-&gt;</span><span class="n">a0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nl">SBI_EXT_0_1_CONSOLE_GETCHAR</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">ret</span> <span class="o">=</span> <span class="nf">sbi_getc</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// ...
</span></span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这就把 <code>id</code> 与相应的服务函数绑定。一个<code>extid</code>对应一个<code>handler</code>。</p>
<p>我们可以在找到<code>SBI_EXT_0_1_CONSOLE_PUTCHAR</code>的值，是与 Linux 内核里定义的值是一致的。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// include/sbi/sbi_ecall_interface.h
</span></span></span><span class="line"><span class="cl"><span class="cm">/* SBI Extension IDs */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define SBI_EXT_0_1_CONSOLE_PUTCHAR		0x1
</span></span></span></code></pre></div><h2 id="ecall-服务调用流程">ecall 服务调用流程</h2>
<ol>
<li>
<p>在 <code>firmware/fw_base.S</code> 中注册了 <code>Machine Mode</code> 的 <code>trap handler</code>，即 <code>sbi_trap_handler</code>；</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="nl">_start_warm:</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Setup trap handler */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">la</span>	<span class="no">a4</span><span class="p">,</span> <span class="no">_trap_handler</span>
</span></span><span class="line"><span class="cl">    <span class="nf">csrw</span>	<span class="no">CSR_MTVEC</span><span class="p">,</span> <span class="no">a4</span>  <span class="cm">/* CSR_MTVEC = _trap_handler */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nl">_trap_handler:</span>
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_SAVE_AND_SETUP_SP_T0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_SAVE_MEPC_MSTATUS</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_CALL_C_ROUTINE</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_RESTORE_MEPC_MSTATUS</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_RESTORE_SP_T0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">mret</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">.macro</span>	<span class="no">TRAP_CALL_C_ROUTINE</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Call C routine */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">add</span>	<span class="no">a0</span><span class="p">,</span> <span class="no">sp</span><span class="p">,</span> <span class="no">zero</span>
</span></span><span class="line"><span class="cl">    <span class="nf">call</span>	<span class="no">sbi_trap_handler</span>
</span></span><span class="line"><span class="cl"><span class="na">.endm</span>
</span></span></code></pre></div></li>
<li>
<p>在 <code>lib/sbi/sbi_trap.c</code> 中定义了 <code>sbi_trap_handler</code>，处理各种 <code>mcause</code>，比如 <code>Illegal Instructions</code>，<code>Misaligned Load &amp; Store</code>, <code>Supervisor &amp; Machine Ecall</code> 等。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// lib/sbi/sbi_trap.c
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">sbi_trap_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">sbi_trap_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">switch</span> <span class="p">(</span><span class="n">mcause</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_ILLEGAL_INSTRUCTION</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span>  <span class="o">=</span> <span class="nf">sbi_illegal_insn_handler</span><span class="p">(</span><span class="n">mtval</span><span class="p">,</span> <span class="n">regs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_MISALIGNED_LOAD</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span> <span class="o">=</span> <span class="nf">sbi_misaligned_load_handler</span><span class="p">(</span><span class="n">mtval</span><span class="p">,</span> <span class="n">mtval2</span><span class="p">,</span> <span class="n">mtinst</span><span class="p">,</span> <span class="n">regs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_MISALIGNED_STORE</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span>  <span class="o">=</span> <span class="nf">sbi_misaligned_store_handler</span><span class="p">(</span><span class="n">mtval</span><span class="p">,</span> <span class="n">mtval2</span><span class="p">,</span> <span class="n">mtinst</span><span class="p">,</span> <span class="n">regs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_SUPERVISOR_ECALL</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_MACHINE_ECALL</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span>  <span class="o">=</span> <span class="nf">sbi_ecall_handler</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/* If the trap came from S or U mode, redirect it there */</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">epc</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-&gt;</span><span class="n">mepc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">cause</span> <span class="o">=</span> <span class="n">mcause</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">tval</span> <span class="o">=</span> <span class="n">mtval</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">tval2</span> <span class="o">=</span> <span class="n">mtval2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">tinst</span> <span class="o">=</span> <span class="n">mtinst</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span> <span class="o">=</span> <span class="nf">sbi_trap_redirect</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">trap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span></code></pre></div></li>
<li>
<p>在 <code>lib/sbi/sbi_ecall.c</code> 中定义了处理 <code>ecall mcause</code> 的 <code>sbi_ecall_handler</code>，它遍历上面 <code>ecall_exts_list</code> 中注册的各种 <code>ecall</code> 服务。</p>
</li>
<li>
<p><code>sbi_ecall_handler</code> 根据 Linux 内核传递的 <code>ext (extension id)</code> 找到链表中对应的 <code>ecall</code> 服务，执行其中的 <code>handle</code> 函数，该函数根据 <code>fid</code> 执行具体的服务内容。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// lib/sbi/sbi_ecall.c
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">sbi_ecall_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">sbi_trap_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extension_id</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-&gt;</span><span class="n">a7</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">func_id</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-&gt;</span><span class="n">a6</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">sbi_trap_info</span> <span class="n">trap</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">out_val</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 遍历所有 ecall 服务
</span></span></span><span class="line"><span class="cl">    <span class="n">ext</span> <span class="o">=</span> <span class="nf">sbi_ecall_find_extension</span><span class="p">(</span><span class="n">extension_id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">ext</span> <span class="o">&amp;&amp;</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="n">handle</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 如果找到了就执行
</span></span></span><span class="line"><span class="cl">        <span class="n">ret</span> <span class="o">=</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="nf">handle</span><span class="p">(</span><span class="n">extension_id</span><span class="p">,</span> <span class="n">func_id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="n">regs</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">out_val</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">trap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">extension_id</span> <span class="o">&gt;=</span> <span class="n">SBI_EXT_0_1_SET_TIMER</span> <span class="o">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">            <span class="n">extension_id</span> <span class="o">&lt;=</span> <span class="n">SBI_EXT_0_1_SHUTDOWN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">is_0_1_spec</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ret</span> <span class="o">=</span> <span class="n">SBI_ENOTSUPP</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>我们可以发现 <code>extension_id</code> 就是 a7 寄存器，他和我们在 uCore OS 中定义的 <code>SBI_EXT_0_1_CONSOLE_PUTCHAR</code> 是一致的。</p>
</li>
</ol>
<h1 id="程序的内存布局与编译流程">程序的内存布局与编译流程</h1>
<h2 id="程序的内存布局">程序的内存布局</h2>
<h1 id="ucore-的编译系统">uCore 的编译系统</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">clean</span> <span class="n">build</span> <span class="n">user</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置伪目标clean、build和user，可以通过命令make来执行这些目标
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">all</span><span class="o">:</span> <span class="n">build_kernel</span>
</span></span><span class="line"><span class="cl"><span class="c"># 默认目标为build_kernel，即执行build_kernel目标下的指令
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">LOG</span> <span class="o">?=</span> error
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量LOG，默认值是error
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">K</span> <span class="o">=</span> os
</span></span><span class="line"><span class="cl"><span class="nv">TOOLPREFIX</span> <span class="o">=</span> riscv64-unknown-elf-
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CC</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>gcc
</span></span><span class="line"><span class="cl"><span class="nv">AS</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>gcc
</span></span><span class="line"><span class="cl"><span class="nv">LD</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>ld
</span></span><span class="line"><span class="cl"><span class="nv">OBJCOPY</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>objcopy
</span></span><span class="line"><span class="cl"><span class="nv">OBJDUMP</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>objdump
</span></span><span class="line"><span class="cl"><span class="nv">PY</span> <span class="o">=</span> python3
</span></span><span class="line"><span class="cl"><span class="nv">GDB</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>gdb
</span></span><span class="line"><span class="cl"><span class="nv">CP</span> <span class="o">=</span> cp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">MKDIR_P</span> <span class="o">=</span> mkdir -p
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">BUILDDIR</span> <span class="o">=</span> build
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">C_SRCS</span> <span class="o">=</span> <span class="k">$(</span>wildcard <span class="nv">$K</span>/*.c<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量C_SRCS，使用wildcard函数匹配所有以.c为后缀的文件，并存储在$K目录下
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">AS_SRCS</span> <span class="o">=</span> <span class="k">$(</span>wildcard <span class="nv">$K</span>/*.S<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量AS_SRCS，使用wildcard函数匹配所有以.S为后缀的文件，并存储在$K目录下
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">C_OBJS</span> <span class="o">=</span> <span class="k">$(</span>addprefix <span class="k">$(</span>BUILDDIR<span class="k">)</span>/, <span class="k">$(</span>addsuffix .o, <span class="k">$(</span>basename <span class="k">$(</span>C_SRCS<span class="k">))))</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量C_OBJS，通过addprefix和addsuffix函数将$(C_SRCS)中的路径替换为$(BUILDDIR)，并将后缀修改为.o
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">AS_OBJS</span> <span class="o">=</span> <span class="k">$(</span>addprefix <span class="k">$(</span>BUILDDIR<span class="k">)</span>/, <span class="k">$(</span>addsuffix .o, <span class="k">$(</span>basename <span class="k">$(</span>AS_SRCS<span class="k">))))</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量AS_OBJS，通过addprefix和addsuffix函数将$(AS_SRCS)中的路径替换为$(BUILDDIR)，并将后缀修改为.o
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">OBJS</span> <span class="o">=</span> <span class="k">$(</span>C_OBJS<span class="k">)</span> <span class="k">$(</span>AS_OBJS<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量OBJS，其值为$(C_OBJS)和$(AS_OBJS)的组合
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">HEADER_DEP</span> <span class="o">=</span> <span class="k">$(</span>addsuffix .d, <span class="k">$(</span>basename <span class="k">$(</span>C_OBJS<span class="k">)))</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量HEADER_DEP，通过addsuffix函数将$(C_OBJS)中的后缀修改为.d
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">-include</span> <span class="k">$(</span><span class="nv">HEADER_DEP</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 包含$(HEADER_DEP)中的.d文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">=</span> -Wall -Werror -O -fno-omit-frame-pointer -ggdb
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量CFLAGS，并赋值为-Wall -Werror -O -fno-omit-frame-pointer -ggdb
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -MD
</span></span><span class="line"><span class="cl"><span class="c"># 将-MD选项追加到CFLAGS变量中，用于自动生成依赖关系文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -mcmodel<span class="o">=</span>medany
</span></span><span class="line"><span class="cl"><span class="c"># 将-mcmodel=medany选项追加到CFLAGS变量中，用于指定内存模型
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -ffreestanding -fno-common -nostdlib -mno-relax
</span></span><span class="line"><span class="cl"><span class="c"># 将-ffreestanding -fno-common -nostdlib -mno-relax选项追加到CFLAGS变量中，用于编译无操作系统环境下的程序
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -I<span class="nv">$K</span>
</span></span><span class="line"><span class="cl"><span class="c"># 将-I$K选项追加到CFLAGS变量中，用于指定头文件搜索路径为$K目录下
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> <span class="k">$(</span>shell <span class="k">$(</span>CC<span class="k">)</span> -fno-stack-protector -E -x c /dev/null &gt;/dev/null 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> -fno-stack-protector<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 将$(CC) -fno-stack-protector -E -x c /dev/null &gt;/dev/null 2&gt;&amp;1 &amp;&amp; echo -fno-stack-protector命令执行结果追加到CFLAGS变量中，用于禁用栈保护机制
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">error)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_ERROR
</span></span><span class="line"><span class="cl"><span class="err">else</span> <span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">warn)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_WARN
</span></span><span class="line"><span class="cl"><span class="err">else</span> <span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">info)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_INFO
</span></span><span class="line"><span class="cl"><span class="err">else</span> <span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">debug)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_DEBUG
</span></span><span class="line"><span class="cl"><span class="err">else</span> <span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">trace)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_TRACE
</span></span><span class="line"><span class="cl"><span class="err">endif</span>
</span></span><span class="line"><span class="cl"><span class="c"># 根据$(LOG)变量的值，向CFLAGS变量追加相应的预处理器选项，相当于添加了一个宏定义，log.h中的LOG_LEVEL_ERROR等宏定义会根据这个宏定义来决定是否生效
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Disable PIE when possible (for Ubuntu 16.10 toolchain)
</span></span></span><span class="line"><span class="cl"><span class="err">ifneq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">shell</span> <span class="k">$(</span><span class="nv">CC</span><span class="k">)</span> -<span class="nv">dumpspecs</span> 2&gt;/<span class="nv">dev</span>/<span class="nv">null</span> | <span class="nv">grep</span> -<span class="nv">e</span> &#39;[^<span class="nv">f</span>]<span class="nv">no</span>-<span class="nv">pie</span>&#39;<span class="k">)</span><span class="err">,)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -fno-pie -no-pie
</span></span><span class="line"><span class="cl"><span class="err">endif</span>
</span></span><span class="line"><span class="cl"><span class="err">ifneq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">shell</span> <span class="k">$(</span><span class="nv">CC</span><span class="k">)</span> -<span class="nv">dumpspecs</span> 2&gt;/<span class="nv">dev</span>/<span class="nv">null</span> | <span class="nv">grep</span> -<span class="nv">e</span> &#39;[^<span class="nv">f</span>]<span class="nv">nopie</span>&#39;<span class="k">)</span><span class="err">,)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -fno-pie -nopie
</span></span><span class="line"><span class="cl"><span class="err">endif</span>
</span></span><span class="line"><span class="cl"><span class="c"># 根据系统环境判断是否支持PIE（位置无关执行）选项，并根据情况向CFLAGS变量追加相应的选项
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">LDFLAGS</span> <span class="o">=</span> -z max-page-size<span class="o">=</span><span class="m">4096</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量LDFLAGS，并赋值为-z max-page-size=4096
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(AS_OBJS)</span><span class="o">:</span> <span class="k">$(</span><span class="nv">BUILDDIR</span><span class="k">)</span>/$<span class="n">K</span>/%.<span class="n">o</span> : $<span class="n">K</span>/%.<span class="n">S</span>
</span></span><span class="line"><span class="cl">    @mkdir -p <span class="k">$(</span>@D<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -c $&lt; -o <span class="nv">$@</span>
</span></span><span class="line"><span class="cl"><span class="c"># 规则：生成$(AS_OBJS)目标所需的依赖文件$(BUILDDIR)/$K/%.o，依赖于$K/%.S，并通过$(CC)命令编译生成目标文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(C_OBJS)</span><span class="o">:</span> <span class="k">$(</span><span class="nv">BUILDDIR</span><span class="k">)</span>/$<span class="n">K</span>/%.<span class="n">o</span> : $<span class="n">K</span>/%.<span class="n">c</span>  <span class="k">$(</span><span class="nv">BUILDDIR</span><span class="k">)</span>/$<span class="n">K</span>/%.<span class="n">d</span>
</span></span><span class="line"><span class="cl">    @mkdir -p <span class="k">$(</span>@D<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -c $&lt; -o <span class="nv">$@</span>
</span></span><span class="line"><span class="cl"><span class="c"># 规则：生成$(C_OBJS)目标所需的依赖文件$(BUILDDIR)/$K/%.o，依赖于$K/%.c和$(BUILDDIR)/$K/%.d，并通过$(CC)命令编译生成目标文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(HEADER_DEP)</span><span class="o">:</span> <span class="k">$(</span><span class="nv">BUILDDIR</span><span class="k">)</span>/$<span class="n">K</span>/%.<span class="n">d</span> : $<span class="n">K</span>/%.<span class="n">c</span>
</span></span><span class="line"><span class="cl">    @mkdir -p <span class="k">$(</span>@D<span class="k">)</span>
</span></span><span class="line"><span class="cl">    @set -e<span class="p">;</span> rm -f <span class="nv">$@</span><span class="p">;</span> <span class="k">$(</span>CC<span class="k">)</span> -MM $&lt; <span class="k">$(</span>INCLUDEFLAGS<span class="k">)</span> &gt; <span class="nv">$@</span>.<span class="nv">$$$$</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">        sed <span class="s1">&#39;s,\($*\)\.o[ :]*,\1.o $@ : ,g&#39;</span> &lt; <span class="nv">$@</span>.<span class="nv">$$$$</span> &gt; <span class="nv">$@</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">        rm -f <span class="nv">$@</span>.<span class="nv">$$$$</span>
</span></span><span class="line"><span class="cl"><span class="c"># 规则：生成$(HEADER_DEP)目标所需的依赖文件$(BUILDDIR)/$K/%.d，依赖于$K/%.c，并通过$(CC)命令生成依赖关系文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">build</span><span class="o">:</span> <span class="n">build</span>/<span class="n">kernel</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个目标build，其依赖于build/kernel
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">build/kernel</span><span class="o">:</span> <span class="k">$(</span><span class="nv">OBJS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>LD<span class="k">)</span> <span class="k">$(</span>LDFLAGS<span class="k">)</span> -T os/kernel.ld -o <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel <span class="k">$(</span>OBJS<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>OBJDUMP<span class="k">)</span> -S <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel &gt; <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel.asm
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>OBJDUMP<span class="k">)</span> -t <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel <span class="p">|</span> sed <span class="s1">&#39;1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d&#39;</span> &gt; <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel.sym
</span></span><span class="line"><span class="cl">    @echo <span class="s1">&#39;Build kernel done&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c"># 规则：生成build/kernel目标，依赖于$(OBJS)，通过$(LD)命令连接生成kernel，并通过$(OBJDUMP)命令生成汇编文件和符号表
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">clean</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    rm -rf <span class="k">$(</span>BUILDDIR<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># BOARD
</span></span></span><span class="line"><span class="cl"><span class="nv">BOARD</span>		<span class="o">?=</span> qemu
</span></span><span class="line"><span class="cl"><span class="nv">SBI</span>			<span class="o">?=</span> rustsbi
</span></span><span class="line"><span class="cl"><span class="nv">BOOTLOADER</span>	<span class="o">:=</span> ./bootloader/rustsbi-qemu.bin
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">QEMU</span> <span class="o">=</span> qemu-system-riscv64
</span></span><span class="line"><span class="cl"><span class="nv">QEMUOPTS</span> <span class="o">=</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	-nographic <span class="se">\
</span></span></span><span class="line"><span class="cl">	-machine virt <span class="se">\
</span></span></span><span class="line"><span class="cl">	-bios <span class="k">$(</span>BOOTLOADER<span class="k">)</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	-kernel build/kernel	<span class="se">\
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">run</span><span class="o">:</span> <span class="n">build</span>/<span class="n">kernel</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>QEMU<span class="k">)</span> <span class="k">$(</span>QEMUOPTS<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># QEMU&#39;s gdb stub command line changed in 0.11
</span></span></span><span class="line"><span class="cl"><span class="nv">QEMUGDB</span> <span class="o">=</span> <span class="k">$(</span>shell <span class="k">if</span> <span class="k">$(</span>QEMU<span class="k">)</span> -help <span class="p">|</span> grep -q <span class="s1">&#39;^-gdb&#39;</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	<span class="k">then</span> <span class="nb">echo</span> <span class="s2">&#34;-gdb tcp::15234&#34;</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	<span class="k">else</span> <span class="nb">echo</span> <span class="s2">&#34;-s -p 15234&#34;</span><span class="p">;</span> <span class="k">fi</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 启动QEMU并通过GDB调试，此时QEMu会进入后台运行，并暂停执行，等待GDB连接
</span></span></span><span class="line"><span class="cl"><span class="c"># 连接的GDB端口为15234
</span></span></span><span class="line"><span class="cl"><span class="nf">debug</span><span class="o">:</span> <span class="n">build</span>/<span class="n">kernel</span> .<span class="n">gdbinit</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>QEMU<span class="k">)</span> <span class="k">$(</span>QEMUOPTS<span class="k">)</span> -S <span class="k">$(</span>QEMUGDB<span class="k">)</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="cl">	sleep <span class="m">1</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>GDB<span class="k">)</span>
</span></span></code></pre></div><p>编译、运行 uCore 的一些常用命令有如下一些，涉及了后续章节中引入的测试用例中的命令：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make run
</span></span><span class="line"><span class="cl">make debug
</span></span><span class="line"><span class="cl">make clean
</span></span><span class="line"><span class="cl"><span class="c1"># 编译测试用例的前四章</span>
</span></span><span class="line"><span class="cl">make user <span class="nv">CHAPTER</span><span class="o">=</span><span class="m">4</span> <span class="nv">LOG</span><span class="o">=</span>trace
</span></span><span class="line"><span class="cl"><span class="c1"># 编译测试用例的第四章</span>
</span></span><span class="line"><span class="cl">make user <span class="nv">CHAPTER</span><span class="o">=</span>4_only <span class="nv">LOG</span><span class="o">=</span>trace
</span></span><span class="line"><span class="cl"><span class="c1"># 只运行测试用例的第四章</span>
</span></span><span class="line"><span class="cl">make <span class="nb">test</span> <span class="nv">CHAPTER</span><span class="o">=</span>4_only    
</span></span></code></pre></div><h1 id="附录">附录</h1>
<p>makefile 和 qemu</p>
<p>AS = $(TOOLPREFIX)gas  &gt; AS = $(TOOLPREFIX)as</p>
<h1 id="参考资料">参考资料</h1>
<ul>
<li><a href="https://www.jianshu.com/p/790fc612aaa5">终端颜色控制 - 简书</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>uCore 实验第 5 章 - 进程及进程管理</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC5%E7%AB%A0-%E8%BF%9B%E7%A8%8B%E5%8F%8A%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/</link>
      <pubDate>Fri, 08 Sep 2023 10:01:20 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC5%E7%AB%A0-%E8%BF%9B%E7%A8%8B%E5%8F%8A%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/</guid>
      <description>&lt;p&gt;首先，&lt;code&gt;.section .data&lt;/code&gt; 表示定义了一个数据段，在这个段中定义了一系列的全局变量。其中，&lt;code&gt;_app_num&lt;/code&gt; 是一个标签，表示一个 64 位的整数，初始值为 23。接下来是一系列的标签，分别代表了应用程序的起始地址，每个标签都是 64 位的整数。&lt;/p&gt;
&lt;p&gt;接着，&lt;code&gt;.section .data&lt;/code&gt; 后面又出现了一个标签 &lt;code&gt;_app_names&lt;/code&gt;，它是一个字符串数组，包含了一组字符串，分别命名为 &amp;ldquo;ch2b_exit&amp;rdquo;、&amp;ldquo;ch2b_hello_world&amp;rdquo;、&amp;ldquo;ch2b_power&amp;rdquo; 等等。这些字符串名字对应了前面定义的应用程序的起始地址。&lt;/p&gt;
&lt;p&gt;再往下，出现了一个标签 &lt;code&gt;INIT_PROC&lt;/code&gt;，它是一个字符串，表示初始化进程的名称，值为 &amp;ldquo;usershell&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;之后，每个应用程序都有自己的标签和段名，比如 &lt;code&gt;app_0_start&lt;/code&gt;、&lt;code&gt;app_1_start&lt;/code&gt; 等等。每个标签都包含一个指令 &lt;code&gt;.incbin&lt;/code&gt;，它用于将一个二进制文件（以字符串形式指定文件路径）插入到当前段中。&lt;/p&gt;
&lt;h1 id=&#34;进程初始化分析&#34;&gt;进程初始化分析&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;scheduler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;fetch_task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 获取下一个要执行的进程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;swtch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curenv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nextenv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 切换到下一个进程上下文
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Per-process state
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;procstate&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;// 进程状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 进程 ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 进程用户栈虚拟地址 (用户页表)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 进程内核栈虚拟地址 (内核页表)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 进程中断帧
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 用于保存进程内核态的寄存器信息，进程切换时使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;pagetable_t&lt;/span&gt;       &lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// User page table
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;max_page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;program_brk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;heap_bottom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Parent process
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;exit_code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FD_BUFFER_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 系统调用次数统计
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 进程开始运行时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vma&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vmas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NVMA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 虚拟内存区域
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;wait-系统调用的功能&#34;&gt;wait 系统调用的功能&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;wait&lt;/code&gt; 系统调用是用于处理子进程终止状态的系统调用。其主要功能是等待子进程的终止，并获取子进程的退出状态信息。在操作系统中，当一个父进程创建了一个子进程后，通常会使用 &lt;code&gt;wait&lt;/code&gt; 来等待子进程的终止，以便进行后续的处理，如回收子进程的资源或获取其运行结果。&lt;/p&gt;
&lt;p&gt;以下是 &lt;code&gt;wait&lt;/code&gt; 系统调用的主要功能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;等待子进程终止&lt;/strong&gt;：父进程调用 &lt;code&gt;wait&lt;/code&gt; 系统调用后，会进入阻塞状态，等待子进程终止。如果子进程已经终止，那么 &lt;code&gt;wait&lt;/code&gt; 立即返回，否则父进程会一直等待直到子进程终止。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;获取子进程的退出状态&lt;/strong&gt;：&lt;code&gt;wait&lt;/code&gt; 系统调用会获取子进程的退出状态信息，包括子进程的退出码（通常是一个整数）。这个退出码可以告诉父进程子进程的终止情况，例如是否成功执行等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;回收子进程资源&lt;/strong&gt;：一旦子进程终止，其占用的系统资源（如内存、文件描述符等）通常需要由父进程来回收，以避免资源泄漏。&lt;code&gt;wait&lt;/code&gt; 系统调用在等待子进程终止后，会自动回收这些资源。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;处理僵尸进程&lt;/strong&gt;：在某些情况下，子进程可能会在终止后成为僵尸进程，即已经终止但其进程描述符仍然存在。父进程可以使用 &lt;code&gt;wait&lt;/code&gt; 来回收这些僵尸进程，释放相关资源。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;exec&lt;/code&gt;、&lt;code&gt;fork&lt;/code&gt; 和 &lt;code&gt;spawn&lt;/code&gt; 是操作系统中常见的进程管理系统调用，各自具有不同的功能和用途：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;exec&lt;/code&gt; 系统调用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：&lt;code&gt;exec&lt;/code&gt; 系统调用用于在当前进程的上下文中加载并执行一个新的程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：通常在一个进程需要替换自身的执行映像时使用。它会加载一个新的可执行文件，覆盖当前进程的地址空间和代码段，然后开始执行新的程序。这个新程序可以是完全不同的程序，从而允许进程动态切换到不同的应用程序，而不需要创建新的进程。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;fork&lt;/code&gt; 系统调用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：&lt;code&gt;fork&lt;/code&gt; 系统调用用于创建一个与当前进程几乎完全相同的新进程，包括代码、数据和上下文等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：通常用于创建新的进程，新进程称为子进程，它从父进程继承了大部分状态，然后可以在独立的地址空间中执行不同的操作。&lt;code&gt;fork&lt;/code&gt; 创建的子进程是父进程的副本，可以并行执行不同的任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;spawn&lt;/code&gt; 系统调用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：&lt;code&gt;spawn&lt;/code&gt; 系统调用通常用于创建新的进程并执行指定的程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：类似于 &lt;code&gt;fork&lt;/code&gt;，它也创建了一个新的进程，但不像 &lt;code&gt;fork&lt;/code&gt; 那样完全复制父进程。相反，&lt;code&gt;spawn&lt;/code&gt; 允许你指定一个新程序的路径和参数，而不是完全复制当前进程的状态。这使得它更适合用于启动新程序，而不是简单地创建一个进程副本。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;exec&lt;/code&gt; 用于替换当前进程的执行映像，允许加载和执行新程序。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fork&lt;/code&gt; 用于创建一个几乎与父进程相同的新进程，新进程成为父进程的副本。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spawn&lt;/code&gt; 通常用于创建一个新进程并执行指定的程序，允许指定不同的程序路径和参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;附录&#34;&gt;附录&lt;/h1&gt;
&lt;p&gt;本章任务：
在次 -&amp;gt; 在此&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>首先，<code>.section .data</code> 表示定义了一个数据段，在这个段中定义了一系列的全局变量。其中，<code>_app_num</code> 是一个标签，表示一个 64 位的整数，初始值为 23。接下来是一系列的标签，分别代表了应用程序的起始地址，每个标签都是 64 位的整数。</p>
<p>接着，<code>.section .data</code> 后面又出现了一个标签 <code>_app_names</code>，它是一个字符串数组，包含了一组字符串，分别命名为 &ldquo;ch2b_exit&rdquo;、&ldquo;ch2b_hello_world&rdquo;、&ldquo;ch2b_power&rdquo; 等等。这些字符串名字对应了前面定义的应用程序的起始地址。</p>
<p>再往下，出现了一个标签 <code>INIT_PROC</code>，它是一个字符串，表示初始化进程的名称，值为 &ldquo;usershell&rdquo;。</p>
<p>之后，每个应用程序都有自己的标签和段名，比如 <code>app_0_start</code>、<code>app_1_start</code> 等等。每个标签都包含一个指令 <code>.incbin</code>，它用于将一个二进制文件（以字符串形式指定文件路径）插入到当前段中。</p>
<h1 id="进程初始化分析">进程初始化分析</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">scheduler</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fetch_task</span><span class="p">()</span> <span class="c1">// 获取下一个要执行的进程
</span></span></span><span class="line"><span class="cl">    <span class="nf">swtch</span><span class="p">(</span><span class="o">&amp;</span><span class="n">curenv</span><span class="o">-&gt;</span><span class="n">context</span><span class="p">,</span> <span class="n">nextenv</span><span class="o">-&gt;</span><span class="n">context</span><span class="p">)</span> <span class="c1">// 切换到下一个进程上下文
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// Per-process state
</span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">proc</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">enum</span> <span class="n">procstate</span>    <span class="n">state</span><span class="p">;</span>     <span class="c1">// 进程状态
</span></span></span><span class="line"><span class="cl">    <span class="kt">int</span>               <span class="n">pid</span><span class="p">;</span>       <span class="c1">// 进程 ID
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">ustack</span><span class="p">;</span>    <span class="c1">// 进程用户栈虚拟地址 (用户页表)
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">kstack</span><span class="p">;</span>    <span class="c1">// 进程内核栈虚拟地址 (内核页表)
</span></span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">trapframe</span> <span class="o">*</span><span class="n">trapframe</span><span class="p">;</span> <span class="c1">// 进程中断帧
</span></span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">context</span>    <span class="n">context</span><span class="p">;</span> <span class="c1">// 用于保存进程内核态的寄存器信息，进程切换时使用
</span></span></span><span class="line"><span class="cl">    <span class="kt">pagetable_t</span>       <span class="n">pagetable</span><span class="p">;</span> <span class="c1">// User page table
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">max_page</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">program_brk</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">heap_bottom</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span>     <span class="n">parent</span><span class="p">;</span> <span class="c1">// Parent process
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">exit_code</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span>     <span class="n">files</span><span class="p">[</span><span class="n">FD_BUFFER_SIZE</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">uint32</span>     <span class="n">syscall_times</span><span class="p">[</span><span class="n">MAX_SYSCALL_NUM</span><span class="p">];</span> <span class="c1">// 系统调用次数统计
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>     <span class="n">start_time</span><span class="p">;</span>                     <span class="c1">// 进程开始运行时间
</span></span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">vma</span> <span class="n">vmas</span><span class="p">[</span><span class="n">NVMA</span><span class="p">];</span>                     <span class="c1">// 虚拟内存区域
</span></span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="wait-系统调用的功能">wait 系统调用的功能</h2>
<p><code>wait</code> 系统调用是用于处理子进程终止状态的系统调用。其主要功能是等待子进程的终止，并获取子进程的退出状态信息。在操作系统中，当一个父进程创建了一个子进程后，通常会使用 <code>wait</code> 来等待子进程的终止，以便进行后续的处理，如回收子进程的资源或获取其运行结果。</p>
<p>以下是 <code>wait</code> 系统调用的主要功能：</p>
<ol>
<li>
<p><strong>等待子进程终止</strong>：父进程调用 <code>wait</code> 系统调用后，会进入阻塞状态，等待子进程终止。如果子进程已经终止，那么 <code>wait</code> 立即返回，否则父进程会一直等待直到子进程终止。</p>
</li>
<li>
<p><strong>获取子进程的退出状态</strong>：<code>wait</code> 系统调用会获取子进程的退出状态信息，包括子进程的退出码（通常是一个整数）。这个退出码可以告诉父进程子进程的终止情况，例如是否成功执行等。</p>
</li>
<li>
<p><strong>回收子进程资源</strong>：一旦子进程终止，其占用的系统资源（如内存、文件描述符等）通常需要由父进程来回收，以避免资源泄漏。<code>wait</code> 系统调用在等待子进程终止后，会自动回收这些资源。</p>
</li>
<li>
<p><strong>处理僵尸进程</strong>：在某些情况下，子进程可能会在终止后成为僵尸进程，即已经终止但其进程描述符仍然存在。父进程可以使用 <code>wait</code> 来回收这些僵尸进程，释放相关资源。</p>
</li>
</ol>
<p><code>exec</code>、<code>fork</code> 和 <code>spawn</code> 是操作系统中常见的进程管理系统调用，各自具有不同的功能和用途：</p>
<ol>
<li>
<p><strong><code>exec</code> 系统调用</strong>：</p>
<ul>
<li><strong>功能</strong>：<code>exec</code> 系统调用用于在当前进程的上下文中加载并执行一个新的程序。</li>
<li><strong>用途</strong>：通常在一个进程需要替换自身的执行映像时使用。它会加载一个新的可执行文件，覆盖当前进程的地址空间和代码段，然后开始执行新的程序。这个新程序可以是完全不同的程序，从而允许进程动态切换到不同的应用程序，而不需要创建新的进程。</li>
</ul>
</li>
<li>
<p><strong><code>fork</code> 系统调用</strong>：</p>
<ul>
<li><strong>功能</strong>：<code>fork</code> 系统调用用于创建一个与当前进程几乎完全相同的新进程，包括代码、数据和上下文等。</li>
<li><strong>用途</strong>：通常用于创建新的进程，新进程称为子进程，它从父进程继承了大部分状态，然后可以在独立的地址空间中执行不同的操作。<code>fork</code> 创建的子进程是父进程的副本，可以并行执行不同的任务。</li>
</ul>
</li>
<li>
<p><strong><code>spawn</code> 系统调用</strong>：</p>
<ul>
<li><strong>功能</strong>：<code>spawn</code> 系统调用通常用于创建新的进程并执行指定的程序。</li>
<li><strong>用途</strong>：类似于 <code>fork</code>，它也创建了一个新的进程，但不像 <code>fork</code> 那样完全复制父进程。相反，<code>spawn</code> 允许你指定一个新程序的路径和参数，而不是完全复制当前进程的状态。这使得它更适合用于启动新程序，而不是简单地创建一个进程副本。</li>
</ul>
</li>
</ol>
<p>总结：</p>
<ul>
<li><code>exec</code> 用于替换当前进程的执行映像，允许加载和执行新程序。</li>
<li><code>fork</code> 用于创建一个几乎与父进程相同的新进程，新进程成为父进程的副本。</li>
<li><code>spawn</code> 通常用于创建一个新进程并执行指定的程序，允许指定不同的程序路径和参数。</li>
</ul>
<h1 id="附录">附录</h1>
<p>本章任务：
在次 -&gt; 在此</p>
]]></content:encoded>
    </item>
    <item>
      <title>uCore 实验第 4 章 - 地址空间</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC4%E7%AB%A0-%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4/</link>
      <pubDate>Mon, 04 Sep 2023 11:11:48 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC4%E7%AB%A0-%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;为何指定 TRAMPOLINE 和 TRAPFRAME 在 va 的最高位？
TRAMPOLINE 和 TRAPFRAME 被定义在最高的虚拟内存地址上，是因为它们在操作系统的内存布局中起着重要作用。
TRAMPOLINE 被用作从用户模式切换到内核模式的跳转目标。当发生异常或中断时，处理器将从用户模式切换到内核模式，并将控制权转移到内核中预定义的位置，也就是陷阱处理程序。TRAMPOLINE 页面被映射到最高虚拟地址，以便处理器能够在这个转换过程中方便地引用它。通过将其放置在最高地址，确保了无论系统的具体内存布局如何，它始终是可访问的。
另一方面，TRAPFRAME 用于在发生异常或中断时存储机器状态。它包含寄存器、标志和其他操作系统处理异常所需的信息。TRAPFRAME 也被放置在最高的虚拟地址上，以确保它易于访问，并且陷阱处理程序可以高效地访问它。
通过将 TRAMPOLINE 和 TRAPFRAME 定义在最高的虚拟内存地址上，内核可以方便而可靠地处理异常和中断，而无需关心它们在内存中的特定位置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;如何确定分页方案---satp&#34;&gt;如何确定分页方案 - satp&lt;/h1&gt;
&lt;p&gt;在 MMU 没有使能的情况下，虚拟地址和物理地址是相同的。在 MMU 使能的情况下，虚拟地址会被转换成物理地址。这个转换过程是由操作系统来管理的，操作系统需要维护一个数据结构来记录虚拟地址和物理地址的映射关系。这个数据结构就是页表。&lt;/p&gt;
&lt;p&gt;转换的过程需要分页机制，分页机制有多种。RISC-V 的分页方案以 SvX 的模式命名，其中 X 是以位为单位的&lt;strong&gt;虚拟地址的长度&lt;/strong&gt;。在 RV64 架构下，RISC-V 支持多种分页方案，包括 Sv39，Sv48，Sv57 以及 Sv64。Sv39 最大支持 39 位的虚拟地址，这意味着它可以支持 512 GB 的虚拟地址空间。Sv48 最大支持 48 位的虚拟地址，这意味着它可以支持 256 TB 的虚拟地址空间。我们将在本章中实现 Sv39 分页方案。&lt;/p&gt;
&lt;p&gt;如何开启分页机制呢？RISC-V 的分页机制是通过 satp（Supervisor address translation and protection）寄存器来开启的。satp 寄存器字段分布如下：&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/5d1ec6e9adaf743f7c9abc177cd12eb1.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/5d1ec6e9adaf743f7c9abc177cd12eb1.png&#34; alt=&#34;&#34;  title=&#34;RV64 架构下的 satp 寄存器&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mode 字段可以决定是否开启分页以及分页级数。Mode=0 时，不开启分页；Mode=8 时，开启 Sv39 分页机制。&lt;/li&gt;
&lt;li&gt;ASID（Address Space Identifier，地址空间标识符）域是可选的，它可以用来降低上下文切换的开销。目前我们暂不考虑这个字段的作用。&lt;/li&gt;
&lt;li&gt;PPN（Physical Page Number，物理页号），保存了根页表的物理地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;sv39-多级页表机制&#34;&gt;SV39 多级页表机制&lt;/h1&gt;
&lt;h2 id=&#34;页表项描述&#34;&gt;页表项描述&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/86e06238c562bdd238e868fcd819df3c.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/86e06238c562bdd238e868fcd819df3c.png&#34; alt=&#34;&#34;  title=&#34;Sv39 页表项&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;Sv39 页表项（page-table entry，PTE）的布局，从左到右分别包含如下所述的域：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;V 位决定了该页表项的其余部分是否有效 (V=1 时有效)。若 V=0，则任何遍历到此页表项的虚址转换操作都会导致页错误。&lt;/li&gt;
&lt;li&gt;R、W 和 X 位分别表示此页是否可以读取、写入和执行。如果这三个位都是 0，那么这个页表项是指向下一级页表的指针，否则它是页表树的一个叶节点。&lt;/li&gt;
&lt;li&gt;U 位表示该页是否是用户页面。若 U=0，则 U 模式不能访问此页面，但 S 模式可以。若 U=1，则 U 模式下能访问这个页面，而 S 模式不能。&lt;/li&gt;
&lt;li&gt;G 位表示这个映射是否对所有虚址空间有效，硬件可以用这个信息来提高地址转换的性能。这一位通常只用于属于操作系统的页面。&lt;/li&gt;
&lt;li&gt;A 位表示自从上次 A 位被清除以来，该页面是否被访问过。&lt;/li&gt;
&lt;li&gt;D 位表示自从上次清除 D 位以来页面是否被弄脏（例如被写入）。&lt;/li&gt;
&lt;li&gt;RSW 域留给操作系统使用，它会被硬件忽略。&lt;/li&gt;
&lt;li&gt;PPN 域包含物理页号，这是物理地址的一部分。若这个页表项是一个叶节点，那么 PPN 是转换后物理地址的一部分。否则 PPN 给出下一节页表的地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;虚拟地址转换物理地址过程&#34;&gt;虚拟地址转换物理地址过程&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/48e6ce48ffb827a10371344ad07324c2.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/48e6ce48ffb827a10371344ad07324c2.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;当 satp 寄存器中开启分页时，S 模式和 U 模式中访存的地址都会被视为虚拟地址，需要将其转换为物理地址。虚拟地址转换物理地址的过程如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从 satp 寄存器中读取 PPN，得到根页表的物理地址，为了表述方便，我们将其记做三级页表基地址 satp.PPN；&lt;/li&gt;
&lt;li&gt;从虚拟地址中取出三级虚拟页号 L2&lt;/li&gt;
&lt;li&gt;处理器会读取地址位于 satp.PPN * 4096 + L2 * 4 的页表项，得到下一级页表的基地址 L1.PPN；&lt;/li&gt;
&lt;li&gt;从虚拟地址中取出二级虚拟页号 L1&lt;/li&gt;
&lt;li&gt;处理器会读取地址位于 L1.PPN * 4096 + L1 * 4 的页表项，得到下一级页表的基地址 L0.PPN；&lt;/li&gt;
&lt;li&gt;从虚拟地址中取出一级虚拟页号 L0&lt;/li&gt;
&lt;li&gt;处理器会读取地址位于 L0.PPN * 4096 + L0 * 4 的页表项，得到物理页号 PPN；&lt;/li&gt;
&lt;li&gt;将 PPN 和虚拟地址的低 12 位也就是 Offset 拼接起来，得到物理地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们看代码中是如何实现的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define PTE2PA(pte) (((pte) &amp;gt;&amp;gt; 10) &amp;lt;&amp;lt; 12)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 从虚拟地址中提取三个 9 位的页表索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define PXMASK 0x1FF &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 9
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// PGSHIFT = 12，这段宏定义用于定位 VPNx 的位置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 从虚拟地址 VA 中提取出第 level 级页表的索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define PX(level, va) ((((uint64)(va)) &amp;gt;&amp;gt; PXSHIFT(level)) &amp;amp; PXMASK)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面这三个工具宏可以用来提取虚拟页号 VPN。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 返回页表 pagetable 中与虚拟地址 va 对应的 PTE 的地址。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 如果 alloc != 0，则创建所需的页表页。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// RISC-V Sv39 方案有三级页表页。一个页表页包含 512 个 64 位的 PTEs。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 一个 64 位的虚拟地址被分为五个字段：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//   39..63 -- 必须为零。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//   30..38 -- 2 级索引的 9 位。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//   21..29 -- 1 级索引的 9 位。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//   12..20 -- 0 级索引的 9 位。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//    0..11 -- 页面内的 12 位字节偏移量。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// pagetable 页表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// va 虚拟地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// alloc 页表项不存在时是否分配
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;pte_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;walk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pagetable_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;va&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;va&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAXVA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;panic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;walk&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;level&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;level&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;pte_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;PX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;va&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 通过 PTE 的标志位判断每一级的 pte 是否是有效的（V 位）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PTE_V&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pagetable_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;PTE2PA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// 如果该项无效且 alloc 标志被设置，则分配一个新的页表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// 如果 alloc 参数=0 或者已经没有空闲的内存了，那么遇到中途 V=0 的 pte 整个 walk 过程就会直接退出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alloc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pde_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;kalloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// 清空分配的页表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;memset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PGSIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// 更新页表项，将其指向新分配的页表，并设置有效位 PTE_V
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;PA2PTE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PTE_V&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 返回最低级和虚拟地址的页表项，不是返回物理地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;PX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;va&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每次从虚拟地址 va 中提取出一个虚拟页号，然后根据这个虚拟页号从页表中取出下一级页表的基地址。如果这个页表项无效，那么根据 alloc 参数决定是否分配一个新的页表。如果 alloc 参数为 0 或者已经没有空闲的内存了，那么遇到中途 V=0 的 pte 整个 walk 过程就会直接退出。如果 alloc 参数为 1，那么就会分配一个新的页表，然后将这个页表项指向新分配的页表，并设置有效位 PTE_V。&lt;/p&gt;
&lt;p&gt;我们可以发现 walk 返回的结果不是物理地址，而是页表项的地址。这是因为 walk 函数的作用是将虚拟地址转换为物理地址，而页表项中的 PPN 只是物理地址的一部分，&lt;strong&gt;还需要加上虚拟地址的低 12 位偏移量才能得到物理地址&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;如何建立页表&#34;&gt;如何建立页表&lt;/h2&gt;
&lt;p&gt;前面的过程实际上是以用户的角度来考虑的，也就是给你一个虚拟地址按照分页的规则将其转化成物理地址就能访问了。但是作为一个操作系统，我们还需要多考虑一下，页表是哪来的？我们知道从虚拟地址中去获取页表地址，但是&lt;strong&gt;页表的内容是哪来的呢&lt;/strong&gt;？页表是如何建立起来的呢？这些是需要操作系统来完成的。&lt;/p&gt;
&lt;p&gt;建立页表也就是建立虚拟地址到物理地址的映射关系。也就是给你一个虚拟地址，你需要告诉我如何查到物理地址，实际上这个过程就是建立页表的过程。这个过程也是通过 walk 函数来完成的，从上文我们知道如果页表都建好的情况下 walk 就是不断查页表的过程，那么在没有页表的情况下，walk 还可以建立一个个页表。稍有不同的是，walk 返回的是最后一级页表项的地址，我们需要将物理地址写入这个页表项中。&lt;/p&gt;
&lt;p&gt;在 uCore 中使用 mappages 函数封装了 walk 函数，具体如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define PA2PTE(pa) ((((uint64)pa) &amp;gt;&amp;gt; 12) &amp;lt;&amp;lt; 10)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * 为从虚拟地址 va 开始的页面创建指向物理地址 pa 开始的页表项（PTE）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * 注意：va 和 size 可能不是页面对齐的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * 如果无法分配所需的页表，则返回 0，否则返回 -1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param pagetable 根页表地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param va        虚拟地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param size      映射的字节数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param pa        物理地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param perm      权限位
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @return          成功返回 0，否则返回 -1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;mappages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pagetable_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;va&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;perm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;virtualAddress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lastVirtualAddress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;pte_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 地址必须是页面对齐的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;virtualAddress&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;PGROUNDDOWN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;va&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;lastVirtualAddress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;PGROUNDDOWN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;va&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 返回最低级的虚拟地址的页表项，如果不存在会创建一个新的页表项
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 页表项可能会因为内存不足创建失败，如果创建失败，则返回 -1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;walk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;virtualAddress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 如果 PTE 已经有效，则输出错误信息并返回 -1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PTE_V&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;errorf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;remap&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 将物理地址 pa 转换为页表项，并设置权限位 perm 和 有效位 PTE_V
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;PA2PTE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;perm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PTE_V&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 如果当前是最后一个地址，则结束循环
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;virtualAddress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lastVirtualAddress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;virtualAddress&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PGSIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;pa&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PGSIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;问答作业&#34;&gt;问答作业&lt;/h1&gt;
&lt;h2 id=&#34;请列举-sv39-页表页表项的组成结合课堂内容描述其中的标志位有何作用潜在作用&#34;&gt;请列举 SV39 页表页表项的组成，结合课堂内容，描述其中的标志位有何作用／潜在作用？&lt;/h2&gt;
&lt;p&gt;Sv39 页表页表项的组成如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;有效位 (V)&lt;/strong&gt;：这是页表项的最高位，用于指示页表项是否有效。如果有效位设置为 1，表示页表项有效，可以使用；如果设置为 0，表示页表项无效，禁止使用。这是虚拟内存中页表项的基本有效性标志。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;写入位 (W)&lt;/strong&gt;：这个标志位用于指示是否可以对此页进行写入操作。如果设置为 1，表示允许写入；如果设置为 0，表示禁止写入。它是页表项的访问权限控制标志之一。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户位 (U)&lt;/strong&gt;：用户位用于指示是否允许用户态程序访问此页。如果设置为 1，表示允许用户态访问；如果设置为 0，表示只允许内核态访问。它是页表项的访问权限控制标志之一。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行位 (X)&lt;/strong&gt;：执行位用于指示是否允许执行此页上的指令。如果设置为 1，表示允许执行；如果设置为 0，表示禁止执行。它也是页表项的访问权限控制标志之一。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局位 (G)&lt;/strong&gt;：全局位用于指示此页是否是全局的，即无需 TLB 缓存，通常用于内核页。如果设置为 1，表示是全局的；如果设置为 0，表示不是全局的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;已访问位 (A)&lt;/strong&gt;：已访问位表示是否已经访问过此页，通常由硬件设置。操作系统可以用它来实现页面置换算法，如 LRU。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;已修改位 (D)&lt;/strong&gt;：已修改位表示是否已经对此页进行了写入操作。与已访问位类似，操作系统可以用它来实现页面置换算法。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;物理页框地址 (PPN)&lt;/strong&gt;：这是页表项中存储的物理页框的地址。它指示了虚拟页到物理页的映射关系。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sv39 页表的页表项标志位允许操作系统和硬件实现对虚拟内存的细粒度控制和保护。不同的标志位组合可以实现不同级别的内存保护和权限控制，从而提高系统的安全性和可用性。例如，有效位、写入位、用户位和执行位的不同组合可以实现不同级别的内存保护，使操作系统可以将不同的内存区域分配给用户态和内核态，并设置不同的权限。已访问位和已修改位则用于实现页面置换算法，帮助操作系统决定哪些页面应该被置换出去，以优化内存利用率。全局位可以用于标识全局共享的页，从而节省 TLB 缓存空间。物理页框地址是页表项的核心，它建立了虚拟地址到物理地址的映射关系，使虚拟内存管理成为可能。&lt;/p&gt;
&lt;h2 id=&#34;缺页相关问题&#34;&gt;缺页相关问题&lt;/h2&gt;
&lt;h3 id=&#34;请问哪些异常可能是缺页导致的&#34;&gt;请问哪些异常可能是缺页导致的？&lt;/h3&gt;
&lt;p&gt;缺页异常是由于进程访问的页面不在页表中或者在页表中无效而引发的异常。以下这些异常可能是因为缺页导致的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Load Page Fault（Load 异常）：当进程试图读取一个不在页表中或者无效的页面时，会引发 Load Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 5。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Store Page Fault（Store 异常）：当进程试图写入一个不在页表中或者无效的页面时，会引发 Store Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 7。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Instruction Page Fault（指令页异常）：当进程试图执行一个不在页表中或者无效的页面上的指令时，会引发 Instruction Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 12。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;发生缺页时描述相关的重要寄存器的值lab2-中描述过的可以简单点&#34;&gt;发生缺页时，描述相关的重要寄存器的值（lab2 中描述过的可以简单点）。&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;sepc（Exception Program Counter）：trap 发生时会将当前指令的下一条指令地址写入其中，用于 trap 处理完成后返回。&lt;/li&gt;
&lt;li&gt;stval（Machine Trap Value）：mtval 寄存器包含导致异常的原因，即导致异常的指令的具体信息。例如，如果是缺页异常，那么 mtval 寄存器包含导致缺页异常的虚拟地址。&lt;/li&gt;
&lt;li&gt;scause: 中断/异常发生时， CSR 寄存器 scause 中会记录其信息， Interrupt 位记录是中断还是异常， Exception Code 记录中断/异常的种类。&lt;/li&gt;
&lt;li&gt;sstatus: 记录处理器当前状态，其中 SPP 段记录当前特权等级。&lt;/li&gt;
&lt;li&gt;stvec: 记录处理 trap 的入口地址，现有两种模式  Direct 和 Vectored 。&lt;/li&gt;
&lt;li&gt;sscratch: 其中的值是指向hart相关的S态上下文的指针，比如内核栈的指针。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;以下行为的好处&#34;&gt;以下行为的好处？&lt;/h3&gt;
&lt;p&gt;缺页有两个常见的原因，其一是 Lazy 策略，也就是直到内存页面被访问才实际进行页表操作。比如，一个程序被执行时，进程的代码段理论上需要从磁盘加载到内存。但是 os 并不会马上这样做，而是会保存 .text 段在磁盘的位置信息，在这些代码第一次被执行时才完成从磁盘的加载操作。&lt;/p&gt;
&lt;p&gt;Lazy Loading 策略有以下好处：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;减少初始化开销&lt;/strong&gt;：Lazy Loading 允许操作系统在程序启动时只加载必需的页面，而不是一次性加载整个程序。这可以减少启动时间和初始化开销，因为不需要将整个程序加载到内存中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;节省内存&lt;/strong&gt;：Lazy Loading 策略避免了不必要的内存占用。如果程序的某些部分从不被访问，那么它们就不会被加载到内存中，从而节省了内存资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提高响应速度&lt;/strong&gt;：通过仅在需要时加载页面，Lazy Loading 可以提高系统的响应速度。只有当程序访问某个页面时，操作系统才会执行磁盘加载操作，而不会在程序启动时浪费时间加载可能永远不会被访问的内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更好的磁盘利用率&lt;/strong&gt;：Lazy Loading 允许操作系统将程序的不同部分分散在磁盘上，根据需要加载。这可以提高磁盘利用率，因为不需要在磁盘上为整个程序分配连续的空间。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;请问处理-10g-连续的内存页面需要操作的页表实际大致占用多少内存-给出数量级即可&#34;&gt;请问处理 10G 连续的内存页面，需要操作的页表实际大致占用多少内存 (给出数量级即可)？&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;此外 COW(Copy On Write) 也是常见的容易导致缺页的 Lazy 策略，这个之后再说。其实，我们的 mmap 也可以采取 Lazy 策略，比如：一个用户进程先后申请了 10G 的内存空间，然后用了其中 1M 就直接退出了。按照现在的做法，我们显然亏大了，进行了很多没有意义的页表操作。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;处理 10GB 连续的内存页面所需的页表实际上占用的内存量取决于操作系统的页表结构和管理策略。在 RISC-V 的页表结构中，一个页表项（Page Table Entry，PTE）通常占据 8 字节（64 位系统），其中包括物理页框号和一些标志位。让我们假设一个 PTE 占用 8 字节。&lt;/p&gt;
&lt;p&gt;为了估算 10GB 连续内存页面所需的页表实际占用内存量，我们可以按照以下步骤进行计算：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先，将 10GB 转换为字节数。1GB 等于 1,073,741,824 字节，所以 10GB 等于 10 * 1,073,741,824 = 10,737,418,240 字节。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后，计算每个页面表项覆盖的内存范围。假设每个页面表项管理 4KB（4 * 1024 字节）的内存页面。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;计算需要多少个页面表项来管理 10GB 的内存。这可以通过将 10GB 除以每个页面表项管理的内存范围来实现。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最后，将所需的页面表项数量乘以每个 PTE 的大小来估算所需的总内存量。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;让我们进行具体计算：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内存大小：10,737,418,240 字节&lt;/li&gt;
&lt;li&gt;每个页面表项管理的内存范围：4KB = 4 * 1024 字节&lt;/li&gt;
&lt;li&gt;需要的页面表项数量：10,737,418,240 字节 / 4KB = 2,621,440 个页表项&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;假设每个页表项占用 8 字节，则需要的总内存量为：&lt;/p&gt;
&lt;p&gt;2,621,440 个页表项 * 8 字节/页表项 = 20,971,520 字节&lt;/p&gt;
&lt;p&gt;所以，处理 10GB 连续的内存页面所需的页表实际占用内存量约为 20,971,520 字节，或者大约 20MB。这只是一个估算，实际内存占用可能会因操作系统的管理策略和对齐等因素而有所不同。&lt;/p&gt;
&lt;h3 id=&#34;请简单思考如何才能在现有框架基础上实现-lazy-策略缺页时又如何处理描述合理即可不需要考虑实现&#34;&gt;请简单思考如何才能在现有框架基础上实现 Lazy 策略，缺页时又如何处理？描述合理即可，不需要考虑实现。&lt;/h3&gt;
&lt;p&gt;要在现有框架基础上实现 Lazy 策略，可以采取以下简单思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;延迟加载（Lazy Loading）&lt;/strong&gt;：在用户进程请求内存映射时，不立即将整个内存区域加载到物理内存中。而是仅创建虚拟内存映射和页表项，记录对应的磁盘位置等信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;缺页处理（Page Fault Handling）&lt;/strong&gt;：当用户进程访问虚拟内存中的某个尚未加载的内存页面时，会触发缺页异常。在缺页异常处理程序中，操作系统会根据页表中的磁盘位置信息，将相应的磁盘数据加载到物理内存中，并更新页表项，使其指向新加载的物理页面。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;惰性加载（Demand Paging）&lt;/strong&gt;：为了提高性能，可以采用惰性加载策略，即只加载实际被访问的内存页面，而不是一次性加载整个区域。这可以通过在缺页处理程序中进行懒加载操作来实现。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;内存回收（Memory Reclamation）&lt;/strong&gt;：当系统内存不足时，操作系统可以选择回收一些不常访问的内存页面，将其写回磁盘，并更新页表项为无效。这需要根据页面访问模式和策略来确定哪些页面可以被回收。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;性能优化&lt;/strong&gt;：为了提高性能，可以采用预读取（Prefetching）策略，即在缺页处理时，不仅加载当前访问的页面，还预先加载相邻的页面，以减少未来可能的缺页次数。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;此时页面失效如何表现在页表项-pte-上&#34;&gt;此时页面失效如何表现在页表项 (PTE) 上？&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;缺页的另一个常见原因是 swap 策略，也就是内存页面可能被换到磁盘上了，导致对应页面失效。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dirty bit (D 位)：当页面被修改并且尚未写回到主存时，该位会被设置为 1。如果页面已经被换出到磁盘上，D 位将保持为 1，以指示页面数据已过期。&lt;/p&gt;
&lt;p&gt;Valid bit (V 位)：当页面在主存中有效时，V 位被设置为 1。如果页面被换出到磁盘上，V 位将被清除为 0，表示该页无效。&lt;/p&gt;
&lt;p&gt;通过检查页表项的 D 位和 V 位，操作系统可以确定页面是否需要从磁盘重新加载到内存中。如果 D 位为 1，说明页面需要写回到主存，在将其置为有效之前，必须将页数据从磁盘读取到内存中。如果 V 位为 0，说明页面当前无效，需要将其从磁盘加载到内存中，并将 V 位设置为 1，表示页面有效。&lt;/p&gt;
&lt;h2 id=&#34;双页表与单页表&#34;&gt;双页表与单页表&lt;/h2&gt;
&lt;p&gt;为了防范侧信道攻击，我们的 os 使用了双页表。但是传统的设计一直是单页表的，也就是说，用户线程和对应的内核线程共用同一张页表，只不过内核对应的地址只允许在内核态访问。请结合课堂知识回答如下问题：(备注：这里的单/双的说法仅为自创的通俗说法，并无这个名词概念，详情见 KPTI )&lt;/p&gt;
&lt;h2 id=&#34;单页表情况下如何更换页表&#34;&gt;单页表情况下，如何更换页表？&lt;/h2&gt;
&lt;p&gt;在单页表情况下，页表的更换通常是由操作系统的上下文切换来触发的。当从用户态切换到内核态或从一个进程切换到另一个进程时，操作系统会根据相应的上下文信息加载不同的页表，实现页表的更换。&lt;/p&gt;
&lt;h2 id=&#34;单页表情况下如何控制用户态无法访问内核页面tips看看第一题最后一问&#34;&gt;单页表情况下，如何控制用户态无法访问内核页面？（tips:看看第一题最后一问）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;设置页面权限：内核页面通常会被设置为只能在内核态下访问（例如，设置 PTE_U 位为 0），这样用户态无法访问内核页面。&lt;/li&gt;
&lt;li&gt;操作系统权限：操作系统内核态拥有较高的权限，可以通过特权级别或访问控制机制来确保用户态无法直接访问内核页面。用户程序只能通过系统调用进入内核态，并在内核态下由操作系统执行，从而实现对内核页面的访问控制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;单页表有何优势回答合理即可&#34;&gt;单页表有何优势？（回答合理即可）&lt;/h2&gt;
&lt;p&gt;单页表的主要优势在于简化了地址转换过程，减少了内存访问的开销。由于用户线程和内核线程共享同一张页表，不需要在上下文切换时频繁切换页表，这可以提高地址转换的效率。此外，单页表还可以节省内存，因为不需要为每个用户线程分配独立的页表。&lt;/p&gt;
&lt;h2 id=&#34;双页表实现下何时需要更换页表假设你写一个单页表操作系统你会选择何时更换页表回答合理即可&#34;&gt;双页表实现下，何时需要更换页表？假设你写一个单页表操作系统，你会选择何时更换页表（回答合理即可）？&lt;/h2&gt;
&lt;p&gt;在双页表实现下，页表的更换通常在发生上下文切换时需要。当从用户态切换到内核态或从一个进程切换到另一个进程时，需要加载相应的页表，以确保正确的地址转换。如果操作系统采用了每个进程独立的页表，那么在进程切换时需要更换页表。&lt;/p&gt;
&lt;p&gt;如果我写一个单页表操作系统，我会选择在发生进程切换时更换页表，因为这是最频繁的上下文切换情况之一。在其他情况下，如从用户态切换到内核态，可能不需要更换整张页表，而只需修改页表项的权限位来实现访问控制。这样可以减少页表更换的开销，提高性能。&lt;/p&gt;
&lt;h1 id=&#34;附录&#34;&gt;附录&lt;/h1&gt;
&lt;p&gt;修改user项目中的makefile，删除ch4_&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<blockquote>
<p>为何指定 TRAMPOLINE 和 TRAPFRAME 在 va 的最高位？
TRAMPOLINE 和 TRAPFRAME 被定义在最高的虚拟内存地址上，是因为它们在操作系统的内存布局中起着重要作用。
TRAMPOLINE 被用作从用户模式切换到内核模式的跳转目标。当发生异常或中断时，处理器将从用户模式切换到内核模式，并将控制权转移到内核中预定义的位置，也就是陷阱处理程序。TRAMPOLINE 页面被映射到最高虚拟地址，以便处理器能够在这个转换过程中方便地引用它。通过将其放置在最高地址，确保了无论系统的具体内存布局如何，它始终是可访问的。
另一方面，TRAPFRAME 用于在发生异常或中断时存储机器状态。它包含寄存器、标志和其他操作系统处理异常所需的信息。TRAPFRAME 也被放置在最高的虚拟地址上，以确保它易于访问，并且陷阱处理程序可以高效地访问它。
通过将 TRAMPOLINE 和 TRAPFRAME 定义在最高的虚拟内存地址上，内核可以方便而可靠地处理异常和中断，而无需关心它们在内存中的特定位置。</p>
</blockquote>
<h1 id="如何确定分页方案---satp">如何确定分页方案 - satp</h1>
<p>在 MMU 没有使能的情况下，虚拟地址和物理地址是相同的。在 MMU 使能的情况下，虚拟地址会被转换成物理地址。这个转换过程是由操作系统来管理的，操作系统需要维护一个数据结构来记录虚拟地址和物理地址的映射关系。这个数据结构就是页表。</p>
<p>转换的过程需要分页机制，分页机制有多种。RISC-V 的分页方案以 SvX 的模式命名，其中 X 是以位为单位的<strong>虚拟地址的长度</strong>。在 RV64 架构下，RISC-V 支持多种分页方案，包括 Sv39，Sv48，Sv57 以及 Sv64。Sv39 最大支持 39 位的虚拟地址，这意味着它可以支持 512 GB 的虚拟地址空间。Sv48 最大支持 48 位的虚拟地址，这意味着它可以支持 256 TB 的虚拟地址空间。我们将在本章中实现 Sv39 分页方案。</p>
<p>如何开启分页机制呢？RISC-V 的分页机制是通过 satp（Supervisor address translation and protection）寄存器来开启的。satp 寄存器字段分布如下：</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/5d1ec6e9adaf743f7c9abc177cd12eb1.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/5d1ec6e9adaf743f7c9abc177cd12eb1.png" alt=""  title="RV64 架构下的 satp 寄存器" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<ul>
<li>Mode 字段可以决定是否开启分页以及分页级数。Mode=0 时，不开启分页；Mode=8 时，开启 Sv39 分页机制。</li>
<li>ASID（Address Space Identifier，地址空间标识符）域是可选的，它可以用来降低上下文切换的开销。目前我们暂不考虑这个字段的作用。</li>
<li>PPN（Physical Page Number，物理页号），保存了根页表的物理地址。</li>
</ul>
<h1 id="sv39-多级页表机制">SV39 多级页表机制</h1>
<h2 id="页表项描述">页表项描述</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/86e06238c562bdd238e868fcd819df3c.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/86e06238c562bdd238e868fcd819df3c.png" alt=""  title="Sv39 页表项" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>Sv39 页表项（page-table entry，PTE）的布局，从左到右分别包含如下所述的域：</p>
<ul>
<li>V 位决定了该页表项的其余部分是否有效 (V=1 时有效)。若 V=0，则任何遍历到此页表项的虚址转换操作都会导致页错误。</li>
<li>R、W 和 X 位分别表示此页是否可以读取、写入和执行。如果这三个位都是 0，那么这个页表项是指向下一级页表的指针，否则它是页表树的一个叶节点。</li>
<li>U 位表示该页是否是用户页面。若 U=0，则 U 模式不能访问此页面，但 S 模式可以。若 U=1，则 U 模式下能访问这个页面，而 S 模式不能。</li>
<li>G 位表示这个映射是否对所有虚址空间有效，硬件可以用这个信息来提高地址转换的性能。这一位通常只用于属于操作系统的页面。</li>
<li>A 位表示自从上次 A 位被清除以来，该页面是否被访问过。</li>
<li>D 位表示自从上次清除 D 位以来页面是否被弄脏（例如被写入）。</li>
<li>RSW 域留给操作系统使用，它会被硬件忽略。</li>
<li>PPN 域包含物理页号，这是物理地址的一部分。若这个页表项是一个叶节点，那么 PPN 是转换后物理地址的一部分。否则 PPN 给出下一节页表的地址。</li>
</ul>
<h2 id="虚拟地址转换物理地址过程">虚拟地址转换物理地址过程</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/48e6ce48ffb827a10371344ad07324c2.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2023/09/05/48e6ce48ffb827a10371344ad07324c2.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>当 satp 寄存器中开启分页时，S 模式和 U 模式中访存的地址都会被视为虚拟地址，需要将其转换为物理地址。虚拟地址转换物理地址的过程如下：</p>
<ul>
<li>从 satp 寄存器中读取 PPN，得到根页表的物理地址，为了表述方便，我们将其记做三级页表基地址 satp.PPN；</li>
<li>从虚拟地址中取出三级虚拟页号 L2</li>
<li>处理器会读取地址位于 satp.PPN * 4096 + L2 * 4 的页表项，得到下一级页表的基地址 L1.PPN；</li>
<li>从虚拟地址中取出二级虚拟页号 L1</li>
<li>处理器会读取地址位于 L1.PPN * 4096 + L1 * 4 的页表项，得到下一级页表的基地址 L0.PPN；</li>
<li>从虚拟地址中取出一级虚拟页号 L0</li>
<li>处理器会读取地址位于 L0.PPN * 4096 + L0 * 4 的页表项，得到物理页号 PPN；</li>
<li>将 PPN 和虚拟地址的低 12 位也就是 Offset 拼接起来，得到物理地址。</li>
</ul>
<p>我们看代码中是如何实现的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define PTE2PA(pte) (((pte) &gt;&gt; 10) &lt;&lt; 12)
</span></span></span><span class="line"><span class="cl"><span class="c1">// 从虚拟地址中提取三个 9 位的页表索引
</span></span></span><span class="line"><span class="cl"><span class="cp">#define PXMASK 0x1FF </span><span class="c1">// 9
</span></span></span><span class="line"><span class="cl"><span class="c1">// PGSHIFT = 12，这段宏定义用于定位 VPNx 的位置
</span></span></span><span class="line"><span class="cl"><span class="cp">#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
</span></span></span><span class="line"><span class="cl"><span class="c1">// 从虚拟地址 VA 中提取出第 level 级页表的索引
</span></span></span><span class="line"><span class="cl"><span class="cp">#define PX(level, va) ((((uint64)(va)) &gt;&gt; PXSHIFT(level)) &amp; PXMASK)
</span></span></span></code></pre></div><p>上面这三个工具宏可以用来提取虚拟页号 VPN。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 返回页表 pagetable 中与虚拟地址 va 对应的 PTE 的地址。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 如果 alloc != 0，则创建所需的页表页。
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// RISC-V Sv39 方案有三级页表页。一个页表页包含 512 个 64 位的 PTEs。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 一个 64 位的虚拟地址被分为五个字段：
</span></span></span><span class="line"><span class="cl"><span class="c1">//   39..63 -- 必须为零。
</span></span></span><span class="line"><span class="cl"><span class="c1">//   30..38 -- 2 级索引的 9 位。
</span></span></span><span class="line"><span class="cl"><span class="c1">//   21..29 -- 1 级索引的 9 位。
</span></span></span><span class="line"><span class="cl"><span class="c1">//   12..20 -- 0 级索引的 9 位。
</span></span></span><span class="line"><span class="cl"><span class="c1">//    0..11 -- 页面内的 12 位字节偏移量。
</span></span></span><span class="line"><span class="cl"><span class="c1">// pagetable 页表
</span></span></span><span class="line"><span class="cl"><span class="c1">// va 虚拟地址
</span></span></span><span class="line"><span class="cl"><span class="c1">// alloc 页表项不存在时是否分配
</span></span></span><span class="line"><span class="cl"><span class="kt">pte_t</span> <span class="o">*</span><span class="nf">walk</span><span class="p">(</span><span class="kt">pagetable_t</span> <span class="n">pagetable</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">va</span><span class="p">,</span> <span class="kt">int</span> <span class="n">alloc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">va</span> <span class="o">&gt;=</span> <span class="n">MAXVA</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nf">panic</span><span class="p">(</span><span class="s">&#34;walk&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">level</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">level</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span> <span class="n">level</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">pte_t</span> <span class="o">*</span><span class="n">pte</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">pagetable</span><span class="p">[</span><span class="nf">PX</span><span class="p">(</span><span class="n">level</span><span class="p">,</span> <span class="n">va</span><span class="p">)];</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 通过 PTE 的标志位判断每一级的 pte 是否是有效的（V 位）
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">pte</span> <span class="o">&amp;</span> <span class="n">PTE_V</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">pagetable</span> <span class="o">=</span> <span class="p">(</span><span class="kt">pagetable_t</span><span class="p">)</span><span class="nf">PTE2PA</span><span class="p">(</span><span class="o">*</span><span class="n">pte</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 如果该项无效且 alloc 标志被设置，则分配一个新的页表
</span></span></span><span class="line"><span class="cl">            <span class="c1">// 如果 alloc 参数=0 或者已经没有空闲的内存了，那么遇到中途 V=0 的 pte 整个 walk 过程就会直接退出
</span></span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">alloc</span> <span class="o">||</span> <span class="p">(</span><span class="n">pagetable</span> <span class="o">=</span> <span class="p">(</span><span class="kt">pde_t</span> <span class="o">*</span><span class="p">)</span><span class="nf">kalloc</span><span class="p">())</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 清空分配的页表
</span></span></span><span class="line"><span class="cl">            <span class="nf">memset</span><span class="p">(</span><span class="n">pagetable</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">PGSIZE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 更新页表项，将其指向新分配的页表，并设置有效位 PTE_V
</span></span></span><span class="line"><span class="cl">            <span class="o">*</span><span class="n">pte</span> <span class="o">=</span> <span class="nf">PA2PTE</span><span class="p">(</span><span class="n">pagetable</span><span class="p">)</span> <span class="o">|</span> <span class="n">PTE_V</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 返回最低级和虚拟地址的页表项，不是返回物理地址
</span></span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="o">&amp;</span><span class="n">pagetable</span><span class="p">[</span><span class="nf">PX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">va</span><span class="p">)];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>每次从虚拟地址 va 中提取出一个虚拟页号，然后根据这个虚拟页号从页表中取出下一级页表的基地址。如果这个页表项无效，那么根据 alloc 参数决定是否分配一个新的页表。如果 alloc 参数为 0 或者已经没有空闲的内存了，那么遇到中途 V=0 的 pte 整个 walk 过程就会直接退出。如果 alloc 参数为 1，那么就会分配一个新的页表，然后将这个页表项指向新分配的页表，并设置有效位 PTE_V。</p>
<p>我们可以发现 walk 返回的结果不是物理地址，而是页表项的地址。这是因为 walk 函数的作用是将虚拟地址转换为物理地址，而页表项中的 PPN 只是物理地址的一部分，<strong>还需要加上虚拟地址的低 12 位偏移量才能得到物理地址</strong>。</p>
<h2 id="如何建立页表">如何建立页表</h2>
<p>前面的过程实际上是以用户的角度来考虑的，也就是给你一个虚拟地址按照分页的规则将其转化成物理地址就能访问了。但是作为一个操作系统，我们还需要多考虑一下，页表是哪来的？我们知道从虚拟地址中去获取页表地址，但是<strong>页表的内容是哪来的呢</strong>？页表是如何建立起来的呢？这些是需要操作系统来完成的。</p>
<p>建立页表也就是建立虚拟地址到物理地址的映射关系。也就是给你一个虚拟地址，你需要告诉我如何查到物理地址，实际上这个过程就是建立页表的过程。这个过程也是通过 walk 函数来完成的，从上文我们知道如果页表都建好的情况下 walk 就是不断查页表的过程，那么在没有页表的情况下，walk 还可以建立一个个页表。稍有不同的是，walk 返回的是最后一级页表项的地址，我们需要将物理地址写入这个页表项中。</p>
<p>在 uCore 中使用 mappages 函数封装了 walk 函数，具体如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define PA2PTE(pa) ((((uint64)pa) &gt;&gt; 12) &lt;&lt; 10)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 为从虚拟地址 va 开始的页面创建指向物理地址 pa 开始的页表项（PTE）
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 注意：va 和 size 可能不是页面对齐的
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 如果无法分配所需的页表，则返回 0，否则返回 -1
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param pagetable 根页表地址
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param va        虚拟地址
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param size      映射的字节数
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param pa        物理地址
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param perm      权限位
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @return          成功返回 0，否则返回 -1
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">mappages</span><span class="p">(</span><span class="kt">pagetable_t</span> <span class="n">pagetable</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">va</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">size</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">pa</span><span class="p">,</span> <span class="kt">int</span> <span class="n">perm</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">uint64</span> <span class="n">virtualAddress</span><span class="p">,</span> <span class="n">lastVirtualAddress</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">pte_t</span> <span class="o">*</span><span class="n">pte</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 地址必须是页面对齐的
</span></span></span><span class="line"><span class="cl">    <span class="n">virtualAddress</span>     <span class="o">=</span> <span class="nf">PGROUNDDOWN</span><span class="p">(</span><span class="n">va</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">lastVirtualAddress</span> <span class="o">=</span> <span class="nf">PGROUNDDOWN</span><span class="p">(</span><span class="n">va</span> <span class="o">+</span> <span class="n">size</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 返回最低级的虚拟地址的页表项，如果不存在会创建一个新的页表项
</span></span></span><span class="line"><span class="cl">        <span class="c1">// 页表项可能会因为内存不足创建失败，如果创建失败，则返回 -1
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">((</span><span class="n">pte</span> <span class="o">=</span> <span class="nf">walk</span><span class="p">(</span><span class="n">pagetable</span><span class="p">,</span> <span class="n">virtualAddress</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 如果 PTE 已经有效，则输出错误信息并返回 -1
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">pte</span> <span class="o">&amp;</span> <span class="n">PTE_V</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nf">errorf</span><span class="p">(</span><span class="s">&#34;remap&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 将物理地址 pa 转换为页表项，并设置权限位 perm 和 有效位 PTE_V
</span></span></span><span class="line"><span class="cl">        <span class="o">*</span><span class="n">pte</span> <span class="o">=</span> <span class="nf">PA2PTE</span><span class="p">(</span><span class="n">pa</span><span class="p">)</span> <span class="o">|</span> <span class="n">perm</span> <span class="o">|</span> <span class="n">PTE_V</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 如果当前是最后一个地址，则结束循环
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">virtualAddress</span> <span class="o">==</span> <span class="n">lastVirtualAddress</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">virtualAddress</span> <span class="o">+=</span> <span class="n">PGSIZE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">pa</span> <span class="o">+=</span> <span class="n">PGSIZE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h1 id="问答作业">问答作业</h1>
<h2 id="请列举-sv39-页表页表项的组成结合课堂内容描述其中的标志位有何作用潜在作用">请列举 SV39 页表页表项的组成，结合课堂内容，描述其中的标志位有何作用／潜在作用？</h2>
<p>Sv39 页表页表项的组成如下：</p>
<ol>
<li><strong>有效位 (V)</strong>：这是页表项的最高位，用于指示页表项是否有效。如果有效位设置为 1，表示页表项有效，可以使用；如果设置为 0，表示页表项无效，禁止使用。这是虚拟内存中页表项的基本有效性标志。</li>
<li><strong>写入位 (W)</strong>：这个标志位用于指示是否可以对此页进行写入操作。如果设置为 1，表示允许写入；如果设置为 0，表示禁止写入。它是页表项的访问权限控制标志之一。</li>
<li><strong>用户位 (U)</strong>：用户位用于指示是否允许用户态程序访问此页。如果设置为 1，表示允许用户态访问；如果设置为 0，表示只允许内核态访问。它是页表项的访问权限控制标志之一。</li>
<li><strong>执行位 (X)</strong>：执行位用于指示是否允许执行此页上的指令。如果设置为 1，表示允许执行；如果设置为 0，表示禁止执行。它也是页表项的访问权限控制标志之一。</li>
<li><strong>全局位 (G)</strong>：全局位用于指示此页是否是全局的，即无需 TLB 缓存，通常用于内核页。如果设置为 1，表示是全局的；如果设置为 0，表示不是全局的。</li>
<li><strong>已访问位 (A)</strong>：已访问位表示是否已经访问过此页，通常由硬件设置。操作系统可以用它来实现页面置换算法，如 LRU。</li>
<li><strong>已修改位 (D)</strong>：已修改位表示是否已经对此页进行了写入操作。与已访问位类似，操作系统可以用它来实现页面置换算法。</li>
<li><strong>物理页框地址 (PPN)</strong>：这是页表项中存储的物理页框的地址。它指示了虚拟页到物理页的映射关系。</li>
</ol>
<p>Sv39 页表的页表项标志位允许操作系统和硬件实现对虚拟内存的细粒度控制和保护。不同的标志位组合可以实现不同级别的内存保护和权限控制，从而提高系统的安全性和可用性。例如，有效位、写入位、用户位和执行位的不同组合可以实现不同级别的内存保护，使操作系统可以将不同的内存区域分配给用户态和内核态，并设置不同的权限。已访问位和已修改位则用于实现页面置换算法，帮助操作系统决定哪些页面应该被置换出去，以优化内存利用率。全局位可以用于标识全局共享的页，从而节省 TLB 缓存空间。物理页框地址是页表项的核心，它建立了虚拟地址到物理地址的映射关系，使虚拟内存管理成为可能。</p>
<h2 id="缺页相关问题">缺页相关问题</h2>
<h3 id="请问哪些异常可能是缺页导致的">请问哪些异常可能是缺页导致的？</h3>
<p>缺页异常是由于进程访问的页面不在页表中或者在页表中无效而引发的异常。以下这些异常可能是因为缺页导致的：</p>
<ul>
<li>
<p>Load Page Fault（Load 异常）：当进程试图读取一个不在页表中或者无效的页面时，会引发 Load Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 5。</p>
</li>
<li>
<p>Store Page Fault（Store 异常）：当进程试图写入一个不在页表中或者无效的页面时，会引发 Store Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 7。</p>
</li>
<li>
<p>Instruction Page Fault（指令页异常）：当进程试图执行一个不在页表中或者无效的页面上的指令时，会引发 Instruction Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 12。</p>
</li>
</ul>
<h3 id="发生缺页时描述相关的重要寄存器的值lab2-中描述过的可以简单点">发生缺页时，描述相关的重要寄存器的值（lab2 中描述过的可以简单点）。</h3>
<ul>
<li>sepc（Exception Program Counter）：trap 发生时会将当前指令的下一条指令地址写入其中，用于 trap 处理完成后返回。</li>
<li>stval（Machine Trap Value）：mtval 寄存器包含导致异常的原因，即导致异常的指令的具体信息。例如，如果是缺页异常，那么 mtval 寄存器包含导致缺页异常的虚拟地址。</li>
<li>scause: 中断/异常发生时， CSR 寄存器 scause 中会记录其信息， Interrupt 位记录是中断还是异常， Exception Code 记录中断/异常的种类。</li>
<li>sstatus: 记录处理器当前状态，其中 SPP 段记录当前特权等级。</li>
<li>stvec: 记录处理 trap 的入口地址，现有两种模式  Direct 和 Vectored 。</li>
<li>sscratch: 其中的值是指向hart相关的S态上下文的指针，比如内核栈的指针。</li>
</ul>
<h3 id="以下行为的好处">以下行为的好处？</h3>
<p>缺页有两个常见的原因，其一是 Lazy 策略，也就是直到内存页面被访问才实际进行页表操作。比如，一个程序被执行时，进程的代码段理论上需要从磁盘加载到内存。但是 os 并不会马上这样做，而是会保存 .text 段在磁盘的位置信息，在这些代码第一次被执行时才完成从磁盘的加载操作。</p>
<p>Lazy Loading 策略有以下好处：</p>
<ol>
<li><strong>减少初始化开销</strong>：Lazy Loading 允许操作系统在程序启动时只加载必需的页面，而不是一次性加载整个程序。这可以减少启动时间和初始化开销，因为不需要将整个程序加载到内存中。</li>
<li><strong>节省内存</strong>：Lazy Loading 策略避免了不必要的内存占用。如果程序的某些部分从不被访问，那么它们就不会被加载到内存中，从而节省了内存资源。</li>
<li><strong>提高响应速度</strong>：通过仅在需要时加载页面，Lazy Loading 可以提高系统的响应速度。只有当程序访问某个页面时，操作系统才会执行磁盘加载操作，而不会在程序启动时浪费时间加载可能永远不会被访问的内容。</li>
<li><strong>更好的磁盘利用率</strong>：Lazy Loading 允许操作系统将程序的不同部分分散在磁盘上，根据需要加载。这可以提高磁盘利用率，因为不需要在磁盘上为整个程序分配连续的空间。</li>
</ol>
<h3 id="请问处理-10g-连续的内存页面需要操作的页表实际大致占用多少内存-给出数量级即可">请问处理 10G 连续的内存页面，需要操作的页表实际大致占用多少内存 (给出数量级即可)？</h3>
<blockquote>
<p>此外 COW(Copy On Write) 也是常见的容易导致缺页的 Lazy 策略，这个之后再说。其实，我们的 mmap 也可以采取 Lazy 策略，比如：一个用户进程先后申请了 10G 的内存空间，然后用了其中 1M 就直接退出了。按照现在的做法，我们显然亏大了，进行了很多没有意义的页表操作。</p>
</blockquote>
<p>处理 10GB 连续的内存页面所需的页表实际上占用的内存量取决于操作系统的页表结构和管理策略。在 RISC-V 的页表结构中，一个页表项（Page Table Entry，PTE）通常占据 8 字节（64 位系统），其中包括物理页框号和一些标志位。让我们假设一个 PTE 占用 8 字节。</p>
<p>为了估算 10GB 连续内存页面所需的页表实际占用内存量，我们可以按照以下步骤进行计算：</p>
<ol>
<li>
<p>首先，将 10GB 转换为字节数。1GB 等于 1,073,741,824 字节，所以 10GB 等于 10 * 1,073,741,824 = 10,737,418,240 字节。</p>
</li>
<li>
<p>然后，计算每个页面表项覆盖的内存范围。假设每个页面表项管理 4KB（4 * 1024 字节）的内存页面。</p>
</li>
<li>
<p>计算需要多少个页面表项来管理 10GB 的内存。这可以通过将 10GB 除以每个页面表项管理的内存范围来实现。</p>
</li>
<li>
<p>最后，将所需的页面表项数量乘以每个 PTE 的大小来估算所需的总内存量。</p>
</li>
</ol>
<p>让我们进行具体计算：</p>
<ul>
<li>内存大小：10,737,418,240 字节</li>
<li>每个页面表项管理的内存范围：4KB = 4 * 1024 字节</li>
<li>需要的页面表项数量：10,737,418,240 字节 / 4KB = 2,621,440 个页表项</li>
</ul>
<p>假设每个页表项占用 8 字节，则需要的总内存量为：</p>
<p>2,621,440 个页表项 * 8 字节/页表项 = 20,971,520 字节</p>
<p>所以，处理 10GB 连续的内存页面所需的页表实际占用内存量约为 20,971,520 字节，或者大约 20MB。这只是一个估算，实际内存占用可能会因操作系统的管理策略和对齐等因素而有所不同。</p>
<h3 id="请简单思考如何才能在现有框架基础上实现-lazy-策略缺页时又如何处理描述合理即可不需要考虑实现">请简单思考如何才能在现有框架基础上实现 Lazy 策略，缺页时又如何处理？描述合理即可，不需要考虑实现。</h3>
<p>要在现有框架基础上实现 Lazy 策略，可以采取以下简单思路：</p>
<ol>
<li>
<p><strong>延迟加载（Lazy Loading）</strong>：在用户进程请求内存映射时，不立即将整个内存区域加载到物理内存中。而是仅创建虚拟内存映射和页表项，记录对应的磁盘位置等信息。</p>
</li>
<li>
<p><strong>缺页处理（Page Fault Handling）</strong>：当用户进程访问虚拟内存中的某个尚未加载的内存页面时，会触发缺页异常。在缺页异常处理程序中，操作系统会根据页表中的磁盘位置信息，将相应的磁盘数据加载到物理内存中，并更新页表项，使其指向新加载的物理页面。</p>
</li>
<li>
<p><strong>惰性加载（Demand Paging）</strong>：为了提高性能，可以采用惰性加载策略，即只加载实际被访问的内存页面，而不是一次性加载整个区域。这可以通过在缺页处理程序中进行懒加载操作来实现。</p>
</li>
<li>
<p><strong>内存回收（Memory Reclamation）</strong>：当系统内存不足时，操作系统可以选择回收一些不常访问的内存页面，将其写回磁盘，并更新页表项为无效。这需要根据页面访问模式和策略来确定哪些页面可以被回收。</p>
</li>
<li>
<p><strong>性能优化</strong>：为了提高性能，可以采用预读取（Prefetching）策略，即在缺页处理时，不仅加载当前访问的页面，还预先加载相邻的页面，以减少未来可能的缺页次数。</p>
</li>
</ol>
<h3 id="此时页面失效如何表现在页表项-pte-上">此时页面失效如何表现在页表项 (PTE) 上？</h3>
<blockquote>
<p>缺页的另一个常见原因是 swap 策略，也就是内存页面可能被换到磁盘上了，导致对应页面失效。</p>
</blockquote>
<p>Dirty bit (D 位)：当页面被修改并且尚未写回到主存时，该位会被设置为 1。如果页面已经被换出到磁盘上，D 位将保持为 1，以指示页面数据已过期。</p>
<p>Valid bit (V 位)：当页面在主存中有效时，V 位被设置为 1。如果页面被换出到磁盘上，V 位将被清除为 0，表示该页无效。</p>
<p>通过检查页表项的 D 位和 V 位，操作系统可以确定页面是否需要从磁盘重新加载到内存中。如果 D 位为 1，说明页面需要写回到主存，在将其置为有效之前，必须将页数据从磁盘读取到内存中。如果 V 位为 0，说明页面当前无效，需要将其从磁盘加载到内存中，并将 V 位设置为 1，表示页面有效。</p>
<h2 id="双页表与单页表">双页表与单页表</h2>
<p>为了防范侧信道攻击，我们的 os 使用了双页表。但是传统的设计一直是单页表的，也就是说，用户线程和对应的内核线程共用同一张页表，只不过内核对应的地址只允许在内核态访问。请结合课堂知识回答如下问题：(备注：这里的单/双的说法仅为自创的通俗说法，并无这个名词概念，详情见 KPTI )</p>
<h2 id="单页表情况下如何更换页表">单页表情况下，如何更换页表？</h2>
<p>在单页表情况下，页表的更换通常是由操作系统的上下文切换来触发的。当从用户态切换到内核态或从一个进程切换到另一个进程时，操作系统会根据相应的上下文信息加载不同的页表，实现页表的更换。</p>
<h2 id="单页表情况下如何控制用户态无法访问内核页面tips看看第一题最后一问">单页表情况下，如何控制用户态无法访问内核页面？（tips:看看第一题最后一问）</h2>
<ul>
<li>设置页面权限：内核页面通常会被设置为只能在内核态下访问（例如，设置 PTE_U 位为 0），这样用户态无法访问内核页面。</li>
<li>操作系统权限：操作系统内核态拥有较高的权限，可以通过特权级别或访问控制机制来确保用户态无法直接访问内核页面。用户程序只能通过系统调用进入内核态，并在内核态下由操作系统执行，从而实现对内核页面的访问控制。</li>
</ul>
<h2 id="单页表有何优势回答合理即可">单页表有何优势？（回答合理即可）</h2>
<p>单页表的主要优势在于简化了地址转换过程，减少了内存访问的开销。由于用户线程和内核线程共享同一张页表，不需要在上下文切换时频繁切换页表，这可以提高地址转换的效率。此外，单页表还可以节省内存，因为不需要为每个用户线程分配独立的页表。</p>
<h2 id="双页表实现下何时需要更换页表假设你写一个单页表操作系统你会选择何时更换页表回答合理即可">双页表实现下，何时需要更换页表？假设你写一个单页表操作系统，你会选择何时更换页表（回答合理即可）？</h2>
<p>在双页表实现下，页表的更换通常在发生上下文切换时需要。当从用户态切换到内核态或从一个进程切换到另一个进程时，需要加载相应的页表，以确保正确的地址转换。如果操作系统采用了每个进程独立的页表，那么在进程切换时需要更换页表。</p>
<p>如果我写一个单页表操作系统，我会选择在发生进程切换时更换页表，因为这是最频繁的上下文切换情况之一。在其他情况下，如从用户态切换到内核态，可能不需要更换整张页表，而只需修改页表项的权限位来实现访问控制。这样可以减少页表更换的开销，提高性能。</p>
<h1 id="附录">附录</h1>
<p>修改user项目中的makefile，删除ch4_</p>
]]></content:encoded>
    </item>
    <item>
      <title>uCore 实验第 3 章 - 多道程序与分时多任务</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC3%E7%AB%A0-%E5%A4%9A%E9%81%93%E7%A8%8B%E5%BA%8F%E4%B8%8E%E5%88%86%E6%97%B6%E5%A4%9A%E4%BB%BB%E5%8A%A1/</link>
      <pubDate>Sat, 02 Sep 2023 16:03:02 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC3%E7%AB%A0-%E5%A4%9A%E9%81%93%E7%A8%8B%E5%BA%8F%E4%B8%8E%E5%88%86%E6%97%B6%E5%A4%9A%E4%BB%BB%E5%8A%A1/</guid>
      <description>&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 启动时初始化进程表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UNUSED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// p - pool 是 p 指向的 proc 在 pool 中的下标，因此 p - pool 变化情况是 0, 1, 2, ..., NPROC - 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;		* LAB1: you may need to initialize your new fields of proc here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;		*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;boot_stack_top&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;current_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;p - pool 表示什么？
假设我们有一个名为 pool 的数组，其中包含了多个类型为 struct proc 的元素，并且有一个指针 p 指向其中的某个元素。
当 p 指向 pool 数组的第一个元素时，p - pool 的结果将是 0，因为指针相对于数组首地址的偏移量为 0。
当 p 指向 pool 数组的第二个元素时，p - pool 的结果将是 1，因为指针相对于数组首地址的偏移量为 1。
以此类推，当 p 指向 pool 数组的第 N 个元素时，p - pool 的结果将是 N-1，因为指针相对于数组首地址的偏移量为 N-1。
总结来说，如果 p 是指向 pool 数组中第 N 个元素的指针，那么 p - pool 的结果将是 N-1。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原调度函数每次都会从 pool 数组的第一个元素开始遍历，这样会导致每次都是从第一个进程开始运行，而不是从上次运行的进程开始运行。需要修改为如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 调度程序永不返回。它循环执行以下操作：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//  - 选择要运行的进程。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//  - 切换以启动运行该进程。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//  - 最终，该进程通过切换将控制权
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//    传递回调度程序。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;scheduler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 初始化指针为 pool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 p 初始化为 last_checked_proc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;                * LAB1：你可能需要在这里初始化进程的起始时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;                */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;current_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nf&#34;&gt;swtch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 更新 last_checked_proc 的值为下一个位置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;lab1&#34;&gt;LAB1&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;             &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;             &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;23&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;          &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;55&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;++++-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;            &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;files&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;changed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;374&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;insertions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;291&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;deletions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b45e85d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b21b0a4&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;loader.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;defs.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;trap.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;app_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app_info_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;49&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;50&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;run_all_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sp&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;USER_STACK_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-		* LAB1: you may need to initialize your new fields of proc here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+		* LAB1: 初始化系统调用数以及进程开始时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; 		*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;nf&#34;&gt;memset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;\&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;No&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newline&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fee3886&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.0&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c69ae5&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;defs.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;loader.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;trap.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;timer.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PAGE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;33&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;34&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;        &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-		* LAB1: you may need to initialize your new fields of proc here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-		*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;nf&#34;&gt;memset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;boot_stack_top&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;47&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;47&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;allocpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PID&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 在进程表中寻找一个未使用的进程。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 如果找到，则初始化在内核中运行所需的状态。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 如果没有空闲的进程，或者内存分配失败，则返回 0。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;81&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;18&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;scheduler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 初始化指针为 pool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 p 初始化为 last_checked_proc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-                * LAB1：你可能需要在这里初始化进程的起始时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+                * LAB1：在这里初始化进程的开始时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;                 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                    &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MILLISECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;n&#34;&gt;current_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;nf&#34;&gt;swtch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;d208c5d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.53576&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bf&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;types.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;NPROC&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;NPROC&lt;/span&gt;           &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 最大进程数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;500&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 最大系统调用数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// Saved registers for kernel context switches.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;42&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;43&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;28&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 进程内核栈虚拟地址 (内核页表)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 进程中断帧
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 用于保存进程内核态的寄存器信息，进程切换时使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;                               &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-	* LAB1: you may need to add some new fields here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+    /*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+	* LAB1: 添加一些新的成员用于新的 sys_task_info 系统调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; 	*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 系统调用次数统计 TODO: 后续改为指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 进程开始运行时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-* LAB1: you may need to define struct for TaskInfo here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+* LAB1: 定义 TaskInfo 结构体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;UnInit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;Ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;Running&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;Exited&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TaskStatus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;TaskStatus&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 进程运行时间统计
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TaskInfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;curr_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;         &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cc5aeb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f54ed86&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;syscall_ids.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;timer.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;trap.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;proc.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;46&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_sched_yield&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_gettimeofday&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TimeVal&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_tz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sec&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usec&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MICROSECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;tracef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sys_gettimeofday cycle = %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sec&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MILLISECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MICROSECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-* LAB1: you may need to define sys_task_info here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/** 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+ * LAB1：此处定义 sys_task_info 函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+ * 查询当前正在执行的任务信息，任务信息包括任务控制块相关信息（任务状态）、任务使用的系统调用次数、任务总运行时长。 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+ */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_task_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TaskInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;curr_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// TODO: proc 检查为空
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MILLISECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;infof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sys_task_info current_time = %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;infof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;proc-&amp;gt;start_time = %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;infof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ti-&amp;gt;time = %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Running&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLEEPING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ZOMBIE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Exited&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UNUSED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UnInit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trap_page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;51&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;nf&#34;&gt;tracef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;syscall %d args = [%x, %x, %x, %x, %x, %x]&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-	* LAB1: you may need to update syscall counter for task info here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+	* LAB1: 更新系统调用次数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; 	*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;curr_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SYS_write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;67&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;101&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_gettimeofday&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TimeVal&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-	* LAB1: you may need to add SYS_taskinfo case here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+	* LAB1: 在此处添加 SYS_task_info 的系统调用处理情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; 	*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SYS_task_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_task_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TaskInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SYS_getpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;nf&#34;&gt;infof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;SYS_getpid %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SYS_getpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;curr_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;nf&#34;&gt;errorf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;unknown syscall %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;05&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a6cb9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.3&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c1a5a9&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;277&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;277&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_io_pgetevents          292
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_rseq                   293
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_kexec_file_load        294
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-* LAB1: you may need to define SYS_task_info here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// LAB1：添加 SYS_task_info 的系统调用号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SYS_task_info&lt;/span&gt;          &lt;span class=&#34;mi&#34;&gt;410&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_pidfd_send_signal  424
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_io_uring_setup     425
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_io_uring_enter     426
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c6ebd14&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.63&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ab45c&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define TICKS_PER_SEC (100)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// QEMU
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define CPU_FREQ                (12500000)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;MILLISECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define MICROSECONDS_PER_SECOND (1000000)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;   &lt;span class=&#34;nf&#34;&gt;set_next_timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 自 Unix 纪元起的秒数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 毫秒数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;usec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 微秒数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TimeVal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mf&#34;&gt;2.34.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;问答作业&#34;&gt;问答作业&lt;/h1&gt;
&lt;h2 id=&#34;问题一&#34;&gt;问题一&lt;/h2&gt;
&lt;p&gt;正确进入 U 态后，程序的特征还应有：使用 S 态特权指令，访问 S 态寄存器后会报错。请同学们可以自行测试这些内容（参考 前三个测例，描述程序出错行为，同时注意注明你使用的 sbi 及其版本。&lt;/p&gt;
&lt;p&gt;测试前三个测试用例指的是&lt;code&gt;uCore-Tutorial-Code-2023S/user/src/&lt;/code&gt; 目录下的三个&lt;code&gt;bad&lt;/code&gt;测试用例，查看&lt;code&gt;user&lt;/code&gt;项目的 Makefile 可以发现在编译时修改&lt;code&gt;CHAPTER&lt;/code&gt;参数值为&lt;code&gt;2_bad&lt;/code&gt;即可编译运行这些测试用例。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; RustSBI version 0.3.0-alpha.2, adapting to RISC-V SBI v1.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.______       __    __      _______.___________.  _______..______   __
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   _  &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    /       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;           &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; /       &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;   _  &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;----&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;---&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;----&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;----&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      /     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;  &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;  &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   _  &amp;lt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\-&lt;/span&gt;---.&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;--&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;.----&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  .----&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; _&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;._____&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\_&lt;/span&gt;_____/ &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_______/       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;__&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_______/    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;______/ &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;__&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Implementation     : RustSBI-QEMU Version 0.2.0-alpha.2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Platform Name      : riscv-virtio,qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Platform SMP       : &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Platform Memory    : 0x80000000..0x88000000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Boot HART          : &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Device Tree Region : 0x87000000..0x87000ef2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Firmware Address   : 0x80000000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Supervisor Address : 0x80200000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; pmp01: 0x00000000..0x80000000 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;-wr&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; pmp02: 0x80000000..0x80200000 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;---&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; pmp03: 0x80200000..0x88000000 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;xwr&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; pmp04: 0x88000000..0x00000000 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;-wr&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;TRACE 0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;load app &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; at 0x0000000080400000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;TRACE 0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;load app &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; at 0x0000000080420000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;TRACE 0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;load app &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; at 0x0000000080440000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO 0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;start scheduler!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;ERROR 1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;unknown trap: 0x0000000000000007, &lt;span class=&#34;nv&#34;&gt;stval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; 0x0000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO 1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;进程 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 以代码 -1 退出
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IllegalInstruction in application, core dumped.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO 2&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;进程 &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; 以代码 -3 退出
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IllegalInstruction in application, core dumped.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO 3&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;进程 &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; 以代码 -3 退出
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;PANIC 3&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; os/loader.c:15: all apps over
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个进程测试用例如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在您提供的代码中，将空指针分配给指针变量*p 后，试图对其进行解引用并将值 0 赋给该指针。由于用户模式下禁止直接访问物理内存，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped.&lt;/p&gt;
&lt;p&gt;在 RISC-V 架构中，U 模式是最低的用户模式，用户程序无法直接访问物理内存或其他特权级别资源。这种限制是为了确保操作系统的安全性和稳定性。&lt;/p&gt;
&lt;p&gt;第二个进程测试用例如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;volatile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sret&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;试图使用汇编语言执行 sret 指令，该指令用于从中断或异常处理程序返回。由于用户模式下禁止直接访问特权级别寄存器，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped。&lt;/p&gt;
&lt;p&gt;第三个进程测试用例如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;volatile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;csrr %0, sstatus&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原因同上，试图使用汇编语言执行 csrr 指令，该指令用于从特权级别寄存器中读取值。由于用户模式下禁止直接访问特权级别寄存器，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped。&lt;/p&gt;
&lt;p&gt;在操作系统代码中，触发异常后会进入&lt;code&gt;void usertrap()&lt;/code&gt; 函数，该函数会根据 &lt;code&gt;scause&lt;/code&gt; 寄存器的值判断异常类型，用例中的结果进入了&lt;code&gt;case IllegalInstruction&lt;/code&gt;，其中 &lt;code&gt;IllegalInstruction = 2&lt;/code&gt;。我们查阅手册 &lt;code&gt;riscv-privileged.pdf&lt;/code&gt; ，可以查到 &lt;code&gt;IllegalInstruction&lt;/code&gt; 的值为 2，与预期相符。&lt;/p&gt;
&lt;h2 id=&#34;问题二&#34;&gt;问题二&lt;/h2&gt;
&lt;p&gt;请结合用例理解 trampoline.S 中两个函数 &lt;code&gt;userret&lt;/code&gt; 和 &lt;code&gt;uservec&lt;/code&gt; 的作用，并回答如下几个问题：&lt;/p&gt;
&lt;h3 id=&#34;l79-刚进入-userret-时a0a1-分别代表了什么值&#34;&gt;L79: 刚进入 &lt;code&gt;userret&lt;/code&gt; 时，&lt;code&gt;a0&lt;/code&gt;、&lt;code&gt;a1&lt;/code&gt; 分别代表了什么值。&lt;/h3&gt;
&lt;p&gt;在进入&lt;code&gt;userret&lt;/code&gt;函数时，&lt;code&gt;a0&lt;/code&gt;和&lt;code&gt;a1&lt;/code&gt;分别代表以下值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;a0&lt;/code&gt;: TRAPFRAME 的地址，指向当前进程的陷阱帧（trapframe）结构体。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a1&lt;/code&gt;: 用户页表的地址，即进程的页表（pagetable）。这个地址会被写入到&lt;code&gt;satp&lt;/code&gt;寄存器中，用于切换到用户模式的页表。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;l87-l88-sfence-指令有何作用为什么要执行该指令当前章节中删掉该指令会导致错误吗&#34;&gt;L87-L88: &lt;code&gt;sfence&lt;/code&gt; 指令有何作用？为什么要执行该指令，当前章节中，删掉该指令会导致错误吗？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;csrw&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;satp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sfence.vma&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;zero&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;sfence&lt;/code&gt;指令（Store Fence）的作用是确保之前的存储操作完成，并且对其他处理器上的核心可见。&lt;/p&gt;
&lt;p&gt;执行&lt;code&gt;sfence&lt;/code&gt;指令的主要目的是为了保证内存访问的顺序性和一致性。在多核处理器系统中，不同的核心可能会有自己的缓存，当一个核心修改了共享内存中的数据时，为了保证其他核心能够看到这个修改，需要使用&lt;code&gt;sfence&lt;/code&gt;指令来刷新缓存并将修改写回共享内存。&lt;/p&gt;
&lt;p&gt;在代码中，&lt;code&gt;sfence&lt;/code&gt;指令被用于确保对用户页表的修改对其他处理器上的核心可见。因为目前我只使用了单核处理器，所以不会出现多核处理器的情况，因此&lt;code&gt;sfence&lt;/code&gt;指令的作用是确保对用户页表的修改对当前核心可见。&lt;/p&gt;
&lt;p&gt;因此，当前章节中，&lt;strong&gt;删掉该指令不会导致错误&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;l96-l125-为何注释中说要除去-a0哪一个地址代表-a0现在-a0-的值存在何处&#34;&gt;L96-L125: 为何注释中说要除去 &lt;code&gt;a0&lt;/code&gt;？哪一个地址代表 &lt;code&gt;a0&lt;/code&gt;？现在 &lt;code&gt;a0&lt;/code&gt; 的值存在何处？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# restore all but a0 from TRAPFRAME
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld ra, 40(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld sp, 48(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld t5, 272(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld t6, 280(a0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;a0&lt;/code&gt; 是&lt;strong&gt;保存在 &lt;code&gt;sscratch&lt;/code&gt; 寄存器中的&lt;/strong&gt;，首先，该代码通过 &lt;code&gt;ld&lt;/code&gt; 指令从 &lt;code&gt;TRAPFRAME&lt;/code&gt; 中加载各个寄存器的值。然后，这些值被存储在相应的寄存器中，以便在恢复用户上下文时使用。&lt;/p&gt;
&lt;p&gt;接下来，代码使用 &lt;code&gt;csrrw&lt;/code&gt; 指令将 sscratch 寄存器的值与 &lt;code&gt;a0&lt;/code&gt;（即 &lt;code&gt;TRAPFRAME&lt;/code&gt;）进行交换。这样做是为了将用户的 &lt;code&gt;a0&lt;/code&gt;（&lt;code&gt;TRAPFRAME&lt;/code&gt;）保存在 &lt;code&gt;sscratch&lt;/code&gt; 寄存器中，以便后续步骤可以正确地恢复用户上下文。&lt;/p&gt;
&lt;p&gt;最后，通过 &lt;code&gt;sret&lt;/code&gt; 指令返回到用户模式，并将控制权交给用户代码。在执行 &lt;code&gt;sret&lt;/code&gt; 指令后，处理器将根据用户上下文中的 &lt;code&gt;sepc&lt;/code&gt; 寄存器的值跳转到用户代码的指令地址。返回的同时，处理器还会自动恢复 &lt;code&gt;sstatus&lt;/code&gt; 寄存器的值，以确保正确的特权级别和中断状态。&lt;/p&gt;
&lt;h3 id=&#34;userret中发生状态切换在哪一条指令为何执行之后会进入用户态&#34;&gt;&lt;code&gt;userret&lt;/code&gt;：中发生状态切换在哪一条指令？为何执行之后会进入用户态？&lt;/h3&gt;
&lt;p&gt;在&lt;code&gt;userret&lt;/code&gt;函数中，发生状态切换的指令是&lt;code&gt;sret&lt;/code&gt;指令。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sret&lt;/code&gt;指令用于从内核模式切换到用户模式，并将控制权交给用户代码。执行&lt;code&gt;sret&lt;/code&gt;指令后，处理器会根据用户上下文中的&lt;code&gt;sepc&lt;/code&gt;寄存器的值跳转到用户代码的指令地址。&lt;/p&gt;
&lt;p&gt;执行&lt;code&gt;sret&lt;/code&gt;指令之后进入用户态的原因是，该指令会自动恢复&lt;code&gt;sstatus&lt;/code&gt;寄存器的值，以确保正确的特权级别和中断状态。当&lt;code&gt;sret&lt;/code&gt;指令执行后，处理器将从内核态切换回用户态，程序将继续执行用户代码。这意味着&lt;code&gt;userret&lt;/code&gt;函数成功完成了从内核切换到用户模式的过程。&lt;/p&gt;
&lt;h3 id=&#34;l29执行之后a0-和-sscratch-中各是什么值为什么&#34;&gt;L29：执行之后，a0 和 sscratch 中各是什么值，为什么？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;csrrw a0, sscratch, a0     
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在执行指令后，&lt;code&gt;a0&lt;/code&gt;和&lt;code&gt;sscratch&lt;/code&gt;中的值发生了互换。&lt;/p&gt;
&lt;p&gt;假设原始&lt;code&gt;a0&lt;/code&gt;寄存器中的值为 X，而&lt;code&gt;sscratch&lt;/code&gt;寄存器中的值为 Y。执行&lt;code&gt;csrrw a0, sscratch, a0&lt;/code&gt;指令后，&lt;code&gt;a0&lt;/code&gt;寄存器中的值变为 Y，而&lt;code&gt;sscratch&lt;/code&gt;寄存器中的值变为 X。&lt;/p&gt;
&lt;p&gt;这是因为&lt;code&gt;csrrw&lt;/code&gt;指令是一个特权指令，用于将某个 CSR（Control and Status Register）的值读取到目标寄存器，然后将目标寄存器的值写回到该 CSR 中。在这里，&lt;code&gt;csrrw a0, sscratch, a0&lt;/code&gt;指令将&lt;code&gt;sscratch&lt;/code&gt;寄存器的值读取到&lt;code&gt;a0&lt;/code&gt;寄存器中，同时将&lt;code&gt;a0&lt;/code&gt;寄存器中的值写回到&lt;code&gt;sscratch&lt;/code&gt;寄存器中，从而实现了两者之间的数据交换。&lt;/p&gt;
&lt;h3 id=&#34;l32-l61-从-trapframe-第几项开始保存为什么是否从该项开始保存了所有的值如果不是为什么&#34;&gt;L32-L61: 从 trapframe 第几项开始保存？为什么？是否从该项开始保存了所有的值，如果不是，为什么？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sd ra, 40(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sd sp, 48(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sd t5, 272(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sd t6, 280(a0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;进入-s-态是哪一条指令发生的&#34;&gt;进入 S 态是哪一条指令发生的？&lt;/h3&gt;
&lt;h3 id=&#34;l75-l76-ld-t0-16a0-执行之后t0中的值是什么解释该值的由来&#34;&gt;L75-L76: &lt;code&gt;ld t0, 16(a0)&lt;/code&gt; 执行之后，&lt;code&gt;t0&lt;/code&gt;中的值是什么，解释该值的由来？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld t0, 16(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;jr t0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ld t0, 16(a0)&lt;/code&gt;就是从 &lt;code&gt;trapframe&lt;/code&gt; 中恢复 &lt;code&gt;t0&lt;/code&gt;寄存器值，&lt;code&gt;t0&lt;/code&gt;保存了&lt;code&gt;kernel_trap&lt;/code&gt;的入口地址。使用 &lt;code&gt;jr t0&lt;/code&gt;，就跳转到了我们早先设定在 &lt;code&gt;trapframe-&amp;gt;kernel_trap&lt;/code&gt; 中的地址，也就是 &lt;code&gt;trap.c&lt;/code&gt; 之中的 &lt;code&gt;usertrap&lt;/code&gt; 函数。这个函数在 &lt;code&gt;main&lt;/code&gt; 的初始化之中已经调用了。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 启动时初始化进程表
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">proc_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">p</span> <span class="o">=</span> <span class="n">pool</span><span class="p">;</span> <span class="n">p</span> <span class="o">&lt;</span> <span class="o">&amp;</span><span class="n">pool</span><span class="p">[</span><span class="n">NPROC</span><span class="p">];</span> <span class="n">p</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">=</span> <span class="n">UNUSED</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// p - pool 是 p 指向的 proc 在 pool 中的下标，因此 p - pool 变化情况是 0, 1, 2, ..., NPROC - 1
</span></span></span><span class="line"><span class="cl">        <span class="n">p</span><span class="o">-&gt;</span><span class="n">kstack</span>    <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">kstack</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span><span class="o">-&gt;</span><span class="n">ustack</span>    <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">ustack</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span><span class="o">-&gt;</span><span class="n">trapframe</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">trapframe</span> <span class="o">*</span><span class="p">)</span><span class="n">trapframe</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">		* LAB1: you may need to initialize your new fields of proc here
</span></span></span><span class="line"><span class="cl"><span class="cm">		*/</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">idle</span><span class="p">.</span><span class="n">kstack</span>  <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">boot_stack_top</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">idle</span><span class="p">.</span><span class="n">pid</span>     <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">current_proc</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">idle</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><blockquote>
<p>p - pool 表示什么？
假设我们有一个名为 pool 的数组，其中包含了多个类型为 struct proc 的元素，并且有一个指针 p 指向其中的某个元素。
当 p 指向 pool 数组的第一个元素时，p - pool 的结果将是 0，因为指针相对于数组首地址的偏移量为 0。
当 p 指向 pool 数组的第二个元素时，p - pool 的结果将是 1，因为指针相对于数组首地址的偏移量为 1。
以此类推，当 p 指向 pool 数组的第 N 个元素时，p - pool 的结果将是 N-1，因为指针相对于数组首地址的偏移量为 N-1。
总结来说，如果 p 是指向 pool 数组中第 N 个元素的指针，那么 p - pool 的结果将是 N-1。</p>
</blockquote>
<p>原调度函数每次都会从 pool 数组的第一个元素开始遍历，这样会导致每次都是从第一个进程开始运行，而不是从上次运行的进程开始运行。需要修改为如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 调度程序永不返回。它循环执行以下操作：
</span></span></span><span class="line"><span class="cl"><span class="c1">//  - 选择要运行的进程。
</span></span></span><span class="line"><span class="cl"><span class="c1">//  - 切换以启动运行该进程。
</span></span></span><span class="line"><span class="cl"><span class="c1">//  - 最终，该进程通过切换将控制权
</span></span></span><span class="line"><span class="cl"><span class="c1">//    传递回调度程序。
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">scheduler</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">last_checked_proc</span> <span class="o">=</span> <span class="n">pool</span><span class="p">;</span> <span class="c1">// 初始化指针为 pool
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="n">p</span> <span class="o">=</span> <span class="n">last_checked_proc</span><span class="p">;</span> <span class="n">p</span> <span class="o">&lt;</span> <span class="o">&amp;</span><span class="n">pool</span><span class="p">[</span><span class="n">NPROC</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">             <span class="n">p</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 将 p 初始化为 last_checked_proc
</span></span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">RUNNABLE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">                * LAB1：你可能需要在这里初始化进程的起始时间
</span></span></span><span class="line"><span class="cl"><span class="cm">                */</span>
</span></span><span class="line"><span class="cl">                <span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span>     <span class="o">=</span> <span class="n">RUNNING</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">current_proc</span> <span class="o">=</span> <span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="nf">swtch</span><span class="p">(</span><span class="o">&amp;</span><span class="n">idle</span><span class="p">.</span><span class="n">context</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">last_checked_proc</span> <span class="o">=</span> <span class="n">pool</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 更新 last_checked_proc 的值为下一个位置
</span></span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h1 id="lab1">LAB1</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="o">---</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span>           <span class="o">|</span>   <span class="mi">5</span> <span class="o">+-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span>             <span class="o">|</span>  <span class="mi">15</span> <span class="o">+-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span>             <span class="o">|</span>  <span class="mi">23</span> <span class="o">+-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span>          <span class="o">|</span>  <span class="mi">55</span> <span class="o">++++-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span>      <span class="o">|</span>   <span class="mi">5</span> <span class="o">+-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span>            <span class="o">|</span>   <span class="mi">2</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl"> <span class="mi">9</span> <span class="n">files</span> <span class="n">changed</span><span class="p">,</span> <span class="mi">374</span> <span class="nf">insertions</span><span class="p">(</span><span class="o">+</span><span class="p">),</span> <span class="mi">291</span> <span class="nf">deletions</span><span class="p">(</span><span class="o">-</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="n">b45e85d</span><span class="p">..</span><span class="n">b21b0a4</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;loader.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;defs.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;trap.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">include</span> <span class="o">&lt;</span><span class="n">string</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">uint64</span>  <span class="n">app_num</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">uint64</span> <span class="o">*</span><span class="n">app_info_ptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">49</span><span class="p">,</span><span class="mi">8</span> <span class="o">+</span><span class="mi">50</span><span class="p">,</span><span class="mi">10</span> <span class="err">@@</span> <span class="kt">int</span> <span class="nf">run_all_app</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">         <span class="n">trapframe</span><span class="o">-&gt;</span><span class="n">sp</span>  <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">ustack</span> <span class="o">+</span> <span class="n">USER_STACK_SIZE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span>       <span class="o">=</span> <span class="n">RUNNABLE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-		* LAB1: you may need to initialize your new fields of proc here
</span></span></span><span class="line"><span class="cl"><span class="cm">+		* LAB1: 初始化系统调用数以及进程开始时间
</span></span></span><span class="line"><span class="cl"><span class="cm"> 		*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="nf">memset</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MAX_SYSCALL_NUM</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">uint32</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">p</span><span class="o">-&gt;</span><span class="n">start_time</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="p">}</span>
</span></span><span class="line"><span class="cl">     <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="err">\</span> <span class="n">No</span> <span class="n">newline</span> <span class="n">at</span> <span class="n">end</span> <span class="n">of</span> <span class="n">file</span>
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="n">fee3886</span><span class="p">.</span><span class="mf">.0</span><span class="n">c69ae5</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">2</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;defs.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;loader.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;trap.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">include</span> <span class="s">&#34;timer.h&#34;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">proc</span> <span class="n">pool</span><span class="p">[</span><span class="n">NPROC</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"> <span class="kt">char</span>        <span class="n">kstack</span><span class="p">[</span><span class="n">NPROC</span><span class="p">][</span><span class="n">PAGE_SIZE</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">33</span><span class="p">,</span><span class="mi">9</span> <span class="o">+</span><span class="mi">34</span><span class="p">,</span><span class="mi">8</span> <span class="err">@@</span> <span class="kt">void</span> <span class="nf">proc_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="n">p</span><span class="o">-&gt;</span><span class="n">kstack</span>    <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">kstack</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">         <span class="n">p</span><span class="o">-&gt;</span><span class="n">ustack</span>    <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">ustack</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">         <span class="n">p</span><span class="o">-&gt;</span><span class="n">trapframe</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">trapframe</span> <span class="o">*</span><span class="p">)</span><span class="n">trapframe</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span>        <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-		* LAB1: you may need to initialize your new fields of proc here
</span></span></span><span class="line"><span class="cl"><span class="cm">-		*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="nf">memset</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MAX_SYSCALL_NUM</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">uint32</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">p</span><span class="o">-&gt;</span><span class="n">start_time</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="p">}</span>
</span></span><span class="line"><span class="cl">     <span class="n">idle</span><span class="p">.</span><span class="n">kstack</span>  <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">boot_stack_top</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="n">idle</span><span class="p">.</span><span class="n">pid</span>     <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">47</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">47</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span> <span class="kt">int</span> <span class="nf">allocpid</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">     <span class="k">static</span> <span class="kt">int</span> <span class="n">PID</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">return</span> <span class="n">PID</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 在进程表中寻找一个未使用的进程。
</span></span></span><span class="line"><span class="cl"> <span class="c1">// 如果找到，则初始化在内核中运行所需的状态。
</span></span></span><span class="line"><span class="cl"> <span class="c1">// 如果没有空闲的进程，或者内存分配失败，则返回 0。
</span></span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">80</span><span class="p">,</span><span class="mi">14</span> <span class="o">+</span><span class="mi">81</span><span class="p">,</span><span class="mi">18</span> <span class="err">@@</span> <span class="kt">void</span> <span class="nf">scheduler</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">last_checked_proc</span> <span class="o">=</span> <span class="n">pool</span><span class="p">;</span> <span class="c1">// 初始化指针为 pool
</span></span></span><span class="line"><span class="cl"><span class="o">-</span>
</span></span><span class="line"><span class="cl">     <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="k">for</span> <span class="p">(</span><span class="n">p</span> <span class="o">=</span> <span class="n">last_checked_proc</span><span class="p">;</span> <span class="n">p</span> <span class="o">&lt;</span> <span class="o">&amp;</span><span class="n">pool</span><span class="p">[</span><span class="n">NPROC</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">              <span class="n">p</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 将 p 初始化为 last_checked_proc
</span></span></span><span class="line"><span class="cl">             <span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">RUNNABLE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                 <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-                * LAB1：你可能需要在这里初始化进程的起始时间
</span></span></span><span class="line"><span class="cl"><span class="cm">+                * LAB1：在这里初始化进程的开始时间
</span></span></span><span class="line"><span class="cl"><span class="cm">                 */</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                <span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">start_time</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                    <span class="n">uint64</span> <span class="n">cycle</span> <span class="o">=</span> <span class="nf">get_cycle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                    <span class="n">p</span><span class="o">-&gt;</span><span class="n">start_time</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                        <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MILLISECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                 <span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span>     <span class="o">=</span> <span class="n">RUNNING</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                 <span class="n">current_proc</span> <span class="o">=</span> <span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                 <span class="nf">swtch</span><span class="p">(</span><span class="o">&amp;</span><span class="n">idle</span><span class="p">.</span><span class="n">context</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="n">d208c5d</span><span class="p">.</span><span class="mf">.53576</span><span class="n">bf</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">3</span><span class="p">,</span><span class="mi">7</span> <span class="o">+</span><span class="mi">3</span><span class="p">,</span><span class="mi">8</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;types.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="o">-</span><span class="err">#</span><span class="n">define</span> <span class="nf">NPROC</span> <span class="p">(</span><span class="mi">16</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">define</span> <span class="nf">NPROC</span>           <span class="p">(</span><span class="mi">16</span><span class="p">)</span>  <span class="c1">// 最大进程数
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">define</span> <span class="nf">MAX_SYSCALL_NUM</span> <span class="p">(</span><span class="mi">500</span><span class="p">)</span> <span class="c1">// 最大系统调用数
</span></span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="c1">// Saved registers for kernel context switches.
</span></span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">context</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">42</span><span class="p">,</span><span class="mi">14</span> <span class="o">+</span><span class="mi">43</span><span class="p">,</span><span class="mi">28</span> <span class="err">@@</span> <span class="k">struct</span> <span class="n">proc</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="n">uint64</span>            <span class="n">kstack</span><span class="p">;</span>    <span class="c1">// 进程内核栈虚拟地址 (内核页表)
</span></span></span><span class="line"><span class="cl">     <span class="k">struct</span> <span class="n">trapframe</span> <span class="o">*</span><span class="n">trapframe</span><span class="p">;</span> <span class="c1">// 进程中断帧
</span></span></span><span class="line"><span class="cl">     <span class="k">struct</span> <span class="n">context</span>    <span class="n">context</span><span class="p">;</span> <span class="c1">// 用于保存进程内核态的寄存器信息，进程切换时使用
</span></span></span><span class="line"><span class="cl"><span class="o">-</span>                               <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-	* LAB1: you may need to add some new fields here
</span></span></span><span class="line"><span class="cl"><span class="cm">+    /*
</span></span></span><span class="line"><span class="cl"><span class="cm">+	* LAB1: 添加一些新的成员用于新的 sys_task_info 系统调用
</span></span></span><span class="line"><span class="cl"><span class="cm"> 	*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint32</span> <span class="n">syscall_times</span><span class="p">[</span><span class="n">MAX_SYSCALL_NUM</span><span class="p">];</span> <span class="c1">// 系统调用次数统计 TODO: 后续改为指针
</span></span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint64</span> <span class="n">start_time</span><span class="p">;</span>                     <span class="c1">// 进程开始运行时间
</span></span></span><span class="line"><span class="cl"> <span class="p">};</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-* LAB1: you may need to define struct for TaskInfo here
</span></span></span><span class="line"><span class="cl"><span class="cm">+* LAB1: 定义 TaskInfo 结构体
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">UnInit</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">Ready</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">Running</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">Exited</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="p">}</span> <span class="n">TaskStatus</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">TaskStatus</span> <span class="n">status</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint32</span>     <span class="n">syscall_times</span><span class="p">[</span><span class="n">MAX_SYSCALL_NUM</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="kt">int</span>        <span class="n">time</span><span class="p">;</span> <span class="c1">// 进程运行时间统计
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="p">}</span> <span class="n">TaskInfo</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="nf">curr_proc</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span>         <span class="nf">exit</span><span class="p">(</span><span class="kt">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="mi">1</span><span class="n">cc5aeb</span><span class="p">..</span><span class="n">f54ed86</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">4</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">4</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;syscall_ids.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;timer.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;trap.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">include</span> <span class="s">&#34;proc.h&#34;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="n">uint64</span> <span class="nf">sys_write</span><span class="p">(</span><span class="kt">int</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">str</span><span class="p">,</span> <span class="n">uint</span> <span class="n">len</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">31</span><span class="p">,</span><span class="mi">14</span> <span class="o">+</span><span class="mi">32</span><span class="p">,</span><span class="mi">46</span> <span class="err">@@</span> <span class="n">uint64</span> <span class="nf">sys_sched_yield</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">uint64</span> <span class="nf">sys_gettimeofday</span><span class="p">(</span><span class="n">TimeVal</span> <span class="o">*</span><span class="n">val</span><span class="p">,</span> <span class="kt">int</span> <span class="n">_tz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="n">uint64</span> <span class="n">cycle</span> <span class="o">=</span> <span class="nf">get_cycle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">sec</span>     <span class="o">=</span> <span class="n">cycle</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">usec</span>    <span class="o">=</span> <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MICROSECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">tracef</span><span class="p">(</span><span class="s">&#34;sys_gettimeofday cycle = %d&#34;</span><span class="p">,</span> <span class="n">cycle</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">sec</span>  <span class="o">=</span> <span class="n">cycle</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">msec</span> <span class="o">=</span> <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MILLISECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">usec</span> <span class="o">=</span> <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MICROSECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="o">-</span><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-* LAB1: you may need to define sys_task_info here
</span></span></span><span class="line"><span class="cl"><span class="cm">-*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="cm">/** 
</span></span></span><span class="line"><span class="cl"><span class="cm">+ * LAB1：此处定义 sys_task_info 函数
</span></span></span><span class="line"><span class="cl"><span class="cm">+ * 查询当前正在执行的任务信息，任务信息包括任务控制块相关信息（任务状态）、任务使用的系统调用次数、任务总运行时长。 
</span></span></span><span class="line"><span class="cl"><span class="cm">+ */</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="kt">int</span> <span class="nf">sys_task_info</span><span class="p">(</span><span class="n">TaskInfo</span> <span class="o">*</span><span class="n">ti</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">proc</span> <span class="o">=</span> <span class="nf">curr_proc</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="c1">// TODO: proc 检查为空
</span></span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">MAX_SYSCALL_NUM</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">proc</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint64</span> <span class="n">cycle</span> <span class="o">=</span> <span class="nf">get_cycle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint64</span> <span class="n">current_time</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MILLISECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">infof</span><span class="p">(</span><span class="s">&#34;sys_task_info current_time = %d&#34;</span><span class="p">,</span> <span class="n">current_time</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">infof</span><span class="p">(</span><span class="s">&#34;proc-&gt;start_time = %d&#34;</span><span class="p">,</span> <span class="n">proc</span><span class="o">-&gt;</span><span class="n">start_time</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">infof</span><span class="p">(</span><span class="s">&#34;ti-&gt;time = %d&#34;</span><span class="p">,</span> <span class="n">current_time</span> <span class="o">-</span> <span class="n">proc</span><span class="o">-&gt;</span><span class="n">start_time</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">RUNNING</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">Running</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">RUNNABLE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">Ready</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">SLEEPING</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">Ready</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">ZOMBIE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">Exited</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">UNUSED</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">UnInit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">time</span> <span class="o">=</span> <span class="n">current_time</span> <span class="o">-</span> <span class="n">proc</span><span class="o">-&gt;</span><span class="n">start_time</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">extern</span> <span class="kt">char</span> <span class="n">trap_page</span><span class="p">[];</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">51</span><span class="p">,</span><span class="mi">8</span> <span class="o">+</span><span class="mi">84</span><span class="p">,</span><span class="mi">9</span> <span class="err">@@</span> <span class="kt">void</span> <span class="nf">syscall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">     <span class="nf">tracef</span><span class="p">(</span><span class="s">&#34;syscall %d args = [%x, %x, %x, %x, %x, %x]&#34;</span><span class="p">,</span> <span class="n">id</span><span class="p">,</span> <span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="n">args</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">5</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">     <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-	* LAB1: you may need to update syscall counter for task info here
</span></span></span><span class="line"><span class="cl"><span class="cm">+	* LAB1: 更新系统调用次数
</span></span></span><span class="line"><span class="cl"><span class="cm"> 	*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">curr_proc</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">[</span><span class="n">id</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">switch</span> <span class="p">(</span><span class="n">id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="k">case</span> <span class="nl">SYS_write</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">         <span class="n">ret</span> <span class="o">=</span> <span class="nf">sys_write</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">args</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">67</span><span class="p">,</span><span class="mi">8</span> <span class="o">+</span><span class="mi">101</span><span class="p">,</span><span class="mi">15</span> <span class="err">@@</span> <span class="kt">void</span> <span class="nf">syscall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">         <span class="n">ret</span> <span class="o">=</span> <span class="nf">sys_gettimeofday</span><span class="p">((</span><span class="n">TimeVal</span> <span class="o">*</span><span class="p">)</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">         <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-	* LAB1: you may need to add SYS_taskinfo case here
</span></span></span><span class="line"><span class="cl"><span class="cm">+	* LAB1: 在此处添加 SYS_task_info 的系统调用处理情况
</span></span></span><span class="line"><span class="cl"><span class="cm"> 	*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">case</span> <span class="nl">SYS_task_info</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ret</span> <span class="o">=</span> <span class="nf">sys_task_info</span><span class="p">((</span><span class="n">TaskInfo</span> <span class="o">*</span><span class="p">)</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">case</span> <span class="nl">SYS_getpid</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="nf">infof</span><span class="p">(</span><span class="s">&#34;SYS_getpid %d&#34;</span><span class="p">,</span> <span class="n">SYS_getpid</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ret</span> <span class="o">=</span> <span class="nf">curr_proc</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">pid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">         <span class="n">ret</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="nf">errorf</span><span class="p">(</span><span class="s">&#34;unknown syscall %d&#34;</span><span class="p">,</span> <span class="n">id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="mo">05</span><span class="n">a6cb9</span><span class="p">.</span><span class="mf">.3</span><span class="n">c1a5a9</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">277</span><span class="p">,</span><span class="mi">9</span> <span class="o">+</span><span class="mi">277</span><span class="p">,</span><span class="mi">8</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_io_pgetevents          292
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_rseq                   293
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_kexec_file_load        294
</span></span></span><span class="line"><span class="cl"><span class="o">-</span><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-* LAB1: you may need to define SYS_task_info here
</span></span></span><span class="line"><span class="cl"><span class="cm">-*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="c1">// LAB1：添加 SYS_task_info 的系统调用号
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">define</span> <span class="n">SYS_task_info</span>          <span class="mi">410</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_pidfd_send_signal  424
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_io_uring_setup     425
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_io_uring_enter     426
</span></span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="n">c6ebd14</span><span class="p">.</span><span class="mf">.63</span><span class="n">ab45c</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">6</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#define TICKS_PER_SEC (100)
</span></span></span><span class="line"><span class="cl"> <span class="c1">// QEMU
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define CPU_FREQ                (12500000)
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">define</span> <span class="nf">MILLISECONDS_PER_SECOND</span> <span class="p">(</span><span class="mi">1000</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#define MICROSECONDS_PER_SECOND (1000000)
</span></span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="n">uint64</span> <span class="nf">get_cycle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">14</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">15</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span> <span class="kt">void</span>   <span class="nf">set_next_timer</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="n">uint64</span> <span class="n">sec</span><span class="p">;</span>  <span class="c1">// 自 Unix 纪元起的秒数
</span></span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint64</span> <span class="n">msec</span><span class="p">;</span> <span class="c1">// 毫秒数
</span></span></span><span class="line"><span class="cl">     <span class="n">uint64</span> <span class="n">usec</span><span class="p">;</span> <span class="c1">// 微秒数
</span></span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="n">TimeVal</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="o">--</span> 
</span></span><span class="line"><span class="cl"><span class="mf">2.34.1</span>
</span></span></code></pre></div><h1 id="问答作业">问答作业</h1>
<h2 id="问题一">问题一</h2>
<p>正确进入 U 态后，程序的特征还应有：使用 S 态特权指令，访问 S 态寄存器后会报错。请同学们可以自行测试这些内容（参考 前三个测例，描述程序出错行为，同时注意注明你使用的 sbi 及其版本。</p>
<p>测试前三个测试用例指的是<code>uCore-Tutorial-Code-2023S/user/src/</code> 目录下的三个<code>bad</code>测试用例，查看<code>user</code>项目的 Makefile 可以发现在编译时修改<code>CHAPTER</code>参数值为<code>2_bad</code>即可编译运行这些测试用例。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> RustSBI version 0.3.0-alpha.2, adapting to RISC-V SBI v1.0.0
</span></span><span class="line"><span class="cl">.______       __    __      _______.___________.  _______..______   __
</span></span><span class="line"><span class="cl"><span class="p">|</span>   _  <span class="se">\ </span>    <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>    /       <span class="p">|</span>           <span class="p">|</span> /       <span class="o">||</span>   _  <span class="se">\ </span><span class="p">|</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>  <span class="p">|</span>_<span class="o">)</span>  <span class="p">|</span>    <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>   <span class="p">|</span>   <span class="o">(</span>----<span class="sb">`</span>---<span class="p">|</span>  <span class="p">|</span>----<span class="sb">`</span><span class="p">|</span>   <span class="o">(</span>----<span class="sb">`</span><span class="p">|</span>  <span class="p">|</span>_<span class="o">)</span>  <span class="o">||</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>      /     <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>    <span class="se">\ </span>  <span class="se">\ </span>      <span class="p">|</span>  <span class="p">|</span>      <span class="se">\ </span>  <span class="se">\ </span>   <span class="p">|</span>   _  &lt; <span class="p">|</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>  <span class="p">|</span><span class="se">\ </span> <span class="se">\-</span>---.<span class="p">|</span>  <span class="sb">`</span>--<span class="err">&#39;</span>  <span class="p">|</span>.----<span class="o">)</span>   <span class="p">|</span>      <span class="p">|</span>  <span class="p">|</span>  .----<span class="o">)</span>   <span class="p">|</span>   <span class="p">|</span>  <span class="p">|</span>_<span class="o">)</span>  <span class="o">||</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> _<span class="p">|</span> <span class="sb">`</span>._____<span class="p">|</span> <span class="se">\_</span>_____/ <span class="p">|</span>_______/       <span class="p">|</span>__<span class="p">|</span>  <span class="p">|</span>_______/    <span class="p">|</span>______/ <span class="p">|</span>__<span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Implementation     : RustSBI-QEMU Version 0.2.0-alpha.2
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Platform Name      : riscv-virtio,qemu
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Platform SMP       : <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Platform Memory    : 0x80000000..0x88000000
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Boot HART          : <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Device Tree Region : 0x87000000..0x87000ef2
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Firmware Address   : 0x80000000
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Supervisor Address : 0x80200000
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> pmp01: 0x00000000..0x80000000 <span class="o">(</span>-wr<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> pmp02: 0x80000000..0x80200000 <span class="o">(</span>---<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> pmp03: 0x80200000..0x88000000 <span class="o">(</span>xwr<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> pmp04: 0x88000000..0x00000000 <span class="o">(</span>-wr<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>TRACE 0<span class="o">]</span>load app <span class="m">0</span> at 0x0000000080400000
</span></span><span class="line"><span class="cl"><span class="o">[</span>TRACE 0<span class="o">]</span>load app <span class="m">1</span> at 0x0000000080420000
</span></span><span class="line"><span class="cl"><span class="o">[</span>TRACE 0<span class="o">]</span>load app <span class="m">2</span> at 0x0000000080440000
</span></span><span class="line"><span class="cl"><span class="o">[</span>INFO 0<span class="o">]</span>start scheduler!
</span></span><span class="line"><span class="cl"><span class="o">[</span>ERROR 1<span class="o">]</span>unknown trap: 0x0000000000000007, <span class="nv">stval</span> <span class="o">=</span> 0x0000000000000000
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>INFO 1<span class="o">]</span>进程 <span class="m">1</span> 以代码 -1 退出
</span></span><span class="line"><span class="cl">IllegalInstruction in application, core dumped.
</span></span><span class="line"><span class="cl"><span class="o">[</span>INFO 2<span class="o">]</span>进程 <span class="m">2</span> 以代码 -3 退出
</span></span><span class="line"><span class="cl">IllegalInstruction in application, core dumped.
</span></span><span class="line"><span class="cl"><span class="o">[</span>INFO 3<span class="o">]</span>进程 <span class="m">3</span> 以代码 -3 退出
</span></span><span class="line"><span class="cl"><span class="o">[</span>PANIC 3<span class="o">]</span> os/loader.c:15: all apps over
</span></span></code></pre></div><p>第一个进程测试用例如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在您提供的代码中，将空指针分配给指针变量*p 后，试图对其进行解引用并将值 0 赋给该指针。由于用户模式下禁止直接访问物理内存，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped.</p>
<p>在 RISC-V 架构中，U 模式是最低的用户模式，用户程序无法直接访问物理内存或其他特权级别资源。这种限制是为了确保操作系统的安全性和稳定性。</p>
<p>第二个进程测试用例如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span><span class="s">&#34;sret&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>试图使用汇编语言执行 sret 指令，该指令用于从中断或异常处理程序返回。由于用户模式下禁止直接访问特权级别寄存器，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped。</p>
<p>第三个进程测试用例如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">uint64</span> <span class="n">x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span><span class="s">&#34;csrr %0, sstatus&#34;</span> <span class="o">:</span> <span class="s">&#34;=r&#34;</span><span class="p">(</span><span class="n">x</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>原因同上，试图使用汇编语言执行 csrr 指令，该指令用于从特权级别寄存器中读取值。由于用户模式下禁止直接访问特权级别寄存器，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped。</p>
<p>在操作系统代码中，触发异常后会进入<code>void usertrap()</code> 函数，该函数会根据 <code>scause</code> 寄存器的值判断异常类型，用例中的结果进入了<code>case IllegalInstruction</code>，其中 <code>IllegalInstruction = 2</code>。我们查阅手册 <code>riscv-privileged.pdf</code> ，可以查到 <code>IllegalInstruction</code> 的值为 2，与预期相符。</p>
<h2 id="问题二">问题二</h2>
<p>请结合用例理解 trampoline.S 中两个函数 <code>userret</code> 和 <code>uservec</code> 的作用，并回答如下几个问题：</p>
<h3 id="l79-刚进入-userret-时a0a1-分别代表了什么值">L79: 刚进入 <code>userret</code> 时，<code>a0</code>、<code>a1</code> 分别代表了什么值。</h3>
<p>在进入<code>userret</code>函数时，<code>a0</code>和<code>a1</code>分别代表以下值：</p>
<ul>
<li><code>a0</code>: TRAPFRAME 的地址，指向当前进程的陷阱帧（trapframe）结构体。</li>
<li><code>a1</code>: 用户页表的地址，即进程的页表（pagetable）。这个地址会被写入到<code>satp</code>寄存器中，用于切换到用户模式的页表。</li>
</ul>
<h3 id="l87-l88-sfence-指令有何作用为什么要执行该指令当前章节中删掉该指令会导致错误吗">L87-L88: <code>sfence</code> 指令有何作用？为什么要执行该指令，当前章节中，删掉该指令会导致错误吗？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="nf">csrw</span> <span class="no">satp</span><span class="p">,</span> <span class="no">a1</span>
</span></span><span class="line"><span class="cl"><span class="nf">sfence.vma</span> <span class="no">zero</span><span class="p">,</span> <span class="no">zero</span>
</span></span></code></pre></div><p><code>sfence</code>指令（Store Fence）的作用是确保之前的存储操作完成，并且对其他处理器上的核心可见。</p>
<p>执行<code>sfence</code>指令的主要目的是为了保证内存访问的顺序性和一致性。在多核处理器系统中，不同的核心可能会有自己的缓存，当一个核心修改了共享内存中的数据时，为了保证其他核心能够看到这个修改，需要使用<code>sfence</code>指令来刷新缓存并将修改写回共享内存。</p>
<p>在代码中，<code>sfence</code>指令被用于确保对用户页表的修改对其他处理器上的核心可见。因为目前我只使用了单核处理器，所以不会出现多核处理器的情况，因此<code>sfence</code>指令的作用是确保对用户页表的修改对当前核心可见。</p>
<p>因此，当前章节中，<strong>删掉该指令不会导致错误</strong>。</p>
<h3 id="l96-l125-为何注释中说要除去-a0哪一个地址代表-a0现在-a0-的值存在何处">L96-L125: 为何注释中说要除去 <code>a0</code>？哪一个地址代表 <code>a0</code>？现在 <code>a0</code> 的值存在何处？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># restore all but a0 from TRAPFRAME
</span></span><span class="line"><span class="cl">ld ra, 40(a0)
</span></span><span class="line"><span class="cl">ld sp, 48(a0)
</span></span><span class="line"><span class="cl">ld t5, 272(a0)
</span></span><span class="line"><span class="cl">ld t6, 280(a0)
</span></span></code></pre></div><p><code>a0</code> 是<strong>保存在 <code>sscratch</code> 寄存器中的</strong>，首先，该代码通过 <code>ld</code> 指令从 <code>TRAPFRAME</code> 中加载各个寄存器的值。然后，这些值被存储在相应的寄存器中，以便在恢复用户上下文时使用。</p>
<p>接下来，代码使用 <code>csrrw</code> 指令将 sscratch 寄存器的值与 <code>a0</code>（即 <code>TRAPFRAME</code>）进行交换。这样做是为了将用户的 <code>a0</code>（<code>TRAPFRAME</code>）保存在 <code>sscratch</code> 寄存器中，以便后续步骤可以正确地恢复用户上下文。</p>
<p>最后，通过 <code>sret</code> 指令返回到用户模式，并将控制权交给用户代码。在执行 <code>sret</code> 指令后，处理器将根据用户上下文中的 <code>sepc</code> 寄存器的值跳转到用户代码的指令地址。返回的同时，处理器还会自动恢复 <code>sstatus</code> 寄存器的值，以确保正确的特权级别和中断状态。</p>
<h3 id="userret中发生状态切换在哪一条指令为何执行之后会进入用户态"><code>userret</code>：中发生状态切换在哪一条指令？为何执行之后会进入用户态？</h3>
<p>在<code>userret</code>函数中，发生状态切换的指令是<code>sret</code>指令。</p>
<p><code>sret</code>指令用于从内核模式切换到用户模式，并将控制权交给用户代码。执行<code>sret</code>指令后，处理器会根据用户上下文中的<code>sepc</code>寄存器的值跳转到用户代码的指令地址。</p>
<p>执行<code>sret</code>指令之后进入用户态的原因是，该指令会自动恢复<code>sstatus</code>寄存器的值，以确保正确的特权级别和中断状态。当<code>sret</code>指令执行后，处理器将从内核态切换回用户态，程序将继续执行用户代码。这意味着<code>userret</code>函数成功完成了从内核切换到用户模式的过程。</p>
<h3 id="l29执行之后a0-和-sscratch-中各是什么值为什么">L29：执行之后，a0 和 sscratch 中各是什么值，为什么？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">csrrw a0, sscratch, a0     
</span></span></code></pre></div><p>在执行指令后，<code>a0</code>和<code>sscratch</code>中的值发生了互换。</p>
<p>假设原始<code>a0</code>寄存器中的值为 X，而<code>sscratch</code>寄存器中的值为 Y。执行<code>csrrw a0, sscratch, a0</code>指令后，<code>a0</code>寄存器中的值变为 Y，而<code>sscratch</code>寄存器中的值变为 X。</p>
<p>这是因为<code>csrrw</code>指令是一个特权指令，用于将某个 CSR（Control and Status Register）的值读取到目标寄存器，然后将目标寄存器的值写回到该 CSR 中。在这里，<code>csrrw a0, sscratch, a0</code>指令将<code>sscratch</code>寄存器的值读取到<code>a0</code>寄存器中，同时将<code>a0</code>寄存器中的值写回到<code>sscratch</code>寄存器中，从而实现了两者之间的数据交换。</p>
<h3 id="l32-l61-从-trapframe-第几项开始保存为什么是否从该项开始保存了所有的值如果不是为什么">L32-L61: 从 trapframe 第几项开始保存？为什么？是否从该项开始保存了所有的值，如果不是，为什么？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sd ra, 40(a0)
</span></span><span class="line"><span class="cl">sd sp, 48(a0)
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">sd t5, 272(a0)
</span></span><span class="line"><span class="cl">sd t6, 280(a0)
</span></span></code></pre></div><h3 id="进入-s-态是哪一条指令发生的">进入 S 态是哪一条指令发生的？</h3>
<h3 id="l75-l76-ld-t0-16a0-执行之后t0中的值是什么解释该值的由来">L75-L76: <code>ld t0, 16(a0)</code> 执行之后，<code>t0</code>中的值是什么，解释该值的由来？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ld t0, 16(a0)
</span></span><span class="line"><span class="cl">jr t0
</span></span></code></pre></div><p><code>ld t0, 16(a0)</code>就是从 <code>trapframe</code> 中恢复 <code>t0</code>寄存器值，<code>t0</code>保存了<code>kernel_trap</code>的入口地址。使用 <code>jr t0</code>，就跳转到了我们早先设定在 <code>trapframe-&gt;kernel_trap</code> 中的地址，也就是 <code>trap.c</code> 之中的 <code>usertrap</code> 函数。这个函数在 <code>main</code> 的初始化之中已经调用了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>yq 为 yaml 文件内容排序</title>
      <link>https://lifeislife.cn/posts/yq%E4%B8%BAyaml%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E6%8E%92%E5%BA%8F/</link>
      <pubDate>Fri, 01 Sep 2023 21:37:25 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/yq%E4%B8%BAyaml%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E6%8E%92%E5%BA%8F/</guid>
      <description>&lt;h1 id=&#34;背景&#34;&gt;背景&lt;/h1&gt;
&lt;p&gt;配置 &lt;code&gt;yaml&lt;/code&gt; 文件时会遇到需要将配置的内容按照键值排序的情况，比如下面这样&lt;code&gt;riscv_fork_list.yaml&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;packages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;accumulo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;abseil-cpp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;acpica-tools&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;acpid&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;activemq&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;afflib&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;adcli&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;adwaita-icon-theme&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;aide&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;alsa-lib&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;amtk&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;anaconda&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-sshd&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;annobin&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;antlr3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-csv&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;aom&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-beanutils&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-daemon&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-el&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-exec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-jexl&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-poi&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-rat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我想按照 &lt;code&gt;name&lt;/code&gt; 的字母顺序排序，可以使用 &lt;code&gt;yq&lt;/code&gt; 工具来实现。&lt;/p&gt;
&lt;h1 id=&#34;安装-yq&#34;&gt;安装 yq&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    chmod +x /usr/bin/yq
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;使用-yq&#34;&gt;使用 yq&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;yq -i &lt;span class=&#34;s1&#34;&gt;&amp;#39;.packages |= sort_by(.name)&amp;#39;&lt;/span&gt; riscv_fork_list.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;packages&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;abseil-cpp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;accumulo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;acpica-tools&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;acpid&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;activemq&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;adcli&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;adwaita-icon-theme&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;afflib&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;aide&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;alsa-lib&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;amtk&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;anaconda&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;annobin&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;antlr3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;aom&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-beanutils&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-csv&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-daemon&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-el&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-exec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-commons-jexl&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-poi&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-rat&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;apache-sshd&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h1 id="背景">背景</h1>
<p>配置 <code>yaml</code> 文件时会遇到需要将配置的内容按照键值排序的情况，比如下面这样<code>riscv_fork_list.yaml</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">packages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">accumulo</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">abseil-cpp</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">acpica-tools</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">acpid</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">activemq</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">afflib</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">adcli</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">adwaita-icon-theme</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">aide</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">alsa-lib</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">amtk</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">anaconda</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-sshd</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">annobin</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">antlr3</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-csv</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">aom</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-beanutils</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-daemon</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-el</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-exec</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-jexl</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-poi</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-rat</span><span class="w">
</span></span></span></code></pre></div><p>我想按照 <code>name</code> 的字母顺序排序，可以使用 <code>yq</code> 工具来实现。</p>
<h1 id="安装-yq">安装 yq</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq <span class="o">&amp;&amp;</span><span class="se">\
</span></span></span><span class="line"><span class="cl">    chmod +x /usr/bin/yq
</span></span></code></pre></div><h1 id="使用-yq">使用 yq</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yq -i <span class="s1">&#39;.packages |= sort_by(.name)&#39;</span> riscv_fork_list.yaml
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">packages</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">abseil-cpp</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">accumulo</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">acpica-tools</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">acpid</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">activemq</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">adcli</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">adwaita-icon-theme</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">afflib</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">aide</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">alsa-lib</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">amtk</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">anaconda</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">annobin</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">antlr3</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">aom</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-beanutils</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-csv</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-daemon</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-el</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-exec</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-commons-jexl</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-poi</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-rat</span><span class="w">
</span></span></span><span class="line"><span class="cl">- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">apache-sshd</span><span class="w">
</span></span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>uCore 实验第 2 章 - 批处理系统</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC2%E7%AB%A0-%E6%89%B9%E5%A4%84%E7%90%86%E7%B3%BB%E7%BB%9F/</link>
      <pubDate>Thu, 31 Aug 2023 23:16:38 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC2%E7%AB%A0-%E6%89%B9%E5%A4%84%E7%90%86%E7%B3%BB%E7%BB%9F/</guid>
      <description>&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;flowchart&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subgraph&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;_entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subgraph&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link_app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;_app_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_app_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subgraph&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subgraph&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;loader_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;run_next_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_next_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;load_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;load_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;_entry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loader_init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;run_next_app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;run_next_app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;loader_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_app_num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">flowchart</span> <span class="n">TB</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraph</span> <span class="n">entry</span><span class="o">.</span><span class="n">S</span>
</span></span><span class="line"><span class="cl">        <span class="n">_entry</span><span class="p">[</span><span class="n">_entry</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraph</span> <span class="n">link_app</span><span class="o">.</span><span class="n">S</span>
</span></span><span class="line"><span class="cl">        <span class="n">_app_num</span><span class="p">[</span><span class="n">_app_num</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraph</span> <span class="n">main</span><span class="o">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl">        <span class="n">main</span><span class="p">[</span><span class="n">main</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraph</span> <span class="n">loader</span><span class="o">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl">        <span class="n">loader_init</span><span class="p">[</span><span class="n">loader_init</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">run_next_app</span><span class="p">[</span><span class="n">run_next_app</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">load_app</span><span class="p">[</span><span class="n">load_app</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">_entry</span> <span class="o">--&gt;</span> <span class="n">main</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span> <span class="o">--&gt;</span> <span class="n">loader_init</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span> <span class="o">--&gt;</span> <span class="n">run_next_app</span>
</span></span><span class="line"><span class="cl">    <span class="n">run_next_app</span> <span class="o">--&gt;</span> <span class="n">load_app</span>
</span></span><span class="line"><span class="cl">    <span class="n">loader_init</span> <span class="o">--&gt;</span> <span class="n">_app_num</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>SSH 免密登录</title>
      <link>https://lifeislife.cn/posts/ssh%E5%85%8D%E5%AF%86%E7%99%BB%E5%BD%95/</link>
      <pubDate>Sat, 12 Aug 2023 09:22:56 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ssh%E5%85%8D%E5%AF%86%E7%99%BB%E5%BD%95/</guid>
      <description>&lt;h1 id=&#34;生成密钥对&#34;&gt;生成密钥对&lt;/h1&gt;
&lt;p&gt;宿主机任意下目录执行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ssh-keygen -t rsa
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Generating public/private rsa key pair.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enter file in which to save the key &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;/home/user/.ssh/id_rsa&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: host2servera_id_rsa
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enter passphrase &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;empty &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; no passphrase&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enter same passphrase again: 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Your identification has been saved in host2servera_id_rsa.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Your public key has been saved in host2servera_id_rsa.pub.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The key fingerprint is:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SHA256:OkWcw+R3x6Z2mzeYQuG033H3N9qIeym3TZKzz6YD8tQ user@ubuntu18
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The key&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;s randomart image is:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+---&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;RSA 2048&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;----+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;        .        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; .   .   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;        B .o. +  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;       . oo.o+   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;        S  ++ ..o&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;       o ..+.A&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      o   +..B+&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;+&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;       .   &lt;span class=&#34;nv&#34;&gt;oo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;@o+&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;           &lt;span class=&#34;nv&#34;&gt;o&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ss&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+----&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;SHA256&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;-----+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一直回车确定，生成公私钥，保存在&lt;code&gt;~/.ssh&lt;/code&gt;目录下。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我在宿主机上生成的公私钥名称为，分别是&lt;code&gt;host2servera_id_rsa&lt;/code&gt;,&lt;code&gt;host2servera_id_rsa.pub&lt;/code&gt;方便我记忆。如果一直回车，那么生成的公私钥名称为&lt;code&gt;id_rsa&lt;/code&gt;，&lt;code&gt;id_rsa.pub&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;发送公钥&#34;&gt;发送公钥&lt;/h1&gt;
&lt;p&gt;将公钥复制到服务器 ServerA 上，以 IP：&lt;code&gt;10.12.193.53&lt;/code&gt; 为例。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ssh-copy-id 10.12.193.53
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输入密码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;, to filter out any that are already installed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/bin/ssh-copy-id: INFO: &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; key&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;s&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; remain to be installed -- &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; you are prompted now it is to install the new keys
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;user@10.12.193.53&lt;span class=&#34;s1&#34;&gt;&amp;#39;s password: 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;Number of key(s) added: 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;Now try logging into the machine, with:   &amp;#34;ssh &amp;#39;&lt;/span&gt;10.12.193.53&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;and check to make sure that only the key(s) you wanted were added.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;默认是把 ServerA 的用户当做 user 进行登录。如果有确定的用户如&lt;code&gt;userA&lt;/code&gt;，就使用&lt;code&gt;ssh-copy-id userA@10.12.193.53&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后就可以直接免密码登录了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh user@10.12.193.53
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 或者&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh userA@10.12.193.53
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果还是需要输入密码，可能&lt;code&gt;ssh-agent&lt;/code&gt;没有启动，执行&lt;code&gt;eval $(ssh-agent)&lt;/code&gt;启动&lt;code&gt;ssh-agent&lt;/code&gt;，然后再次登录即可。然后将私钥添加到&lt;code&gt;ssh-agent&lt;/code&gt;中，执行&lt;code&gt;ssh-add ~/.ssh/host2servera_id_rsa&lt;/code&gt;，然后再次登录即可。&lt;/p&gt;
&lt;h1 id=&#34;配置快捷登录&#34;&gt;配置快捷登录&lt;/h1&gt;
&lt;p&gt;即使免密登录，输入一长串 IP 也太麻烦了，能不能配置更简单的登录方式，比如给服务器起个名字如&lt;code&gt;ServerA&lt;/code&gt;直接使用&lt;code&gt;ssh ServerA&lt;/code&gt;就登录服务器，能。&lt;/p&gt;
&lt;p&gt;打开&lt;code&gt;~/.ssh/config&lt;/code&gt;配置如下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Ini&#34; data-lang=&#34;Ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;Host ServerA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;HostName 10.12.193.53&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;Port 22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;User userA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;IdentityFile ~/.ssh/host2servera_id_rsa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后就可以直接使用&lt;code&gt;ssh ServerA&lt;/code&gt;登录了。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="生成密钥对">生成密钥对</h1>
<p>宿主机任意下目录执行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">$ ssh-keygen -t rsa
</span></span><span class="line"><span class="cl">Generating public/private rsa key pair.
</span></span><span class="line"><span class="cl">Enter file in which to save the key <span class="o">(</span>/home/user/.ssh/id_rsa<span class="o">)</span>: host2servera_id_rsa
</span></span><span class="line"><span class="cl">Enter passphrase <span class="o">(</span>empty <span class="k">for</span> no passphrase<span class="o">)</span>: 
</span></span><span class="line"><span class="cl">Enter same passphrase again: 
</span></span><span class="line"><span class="cl">Your identification has been saved in host2servera_id_rsa.
</span></span><span class="line"><span class="cl">Your public key has been saved in host2servera_id_rsa.pub.
</span></span><span class="line"><span class="cl">The key fingerprint is:
</span></span><span class="line"><span class="cl">SHA256:OkWcw+R3x6Z2mzeYQuG033H3N9qIeym3TZKzz6YD8tQ user@ubuntu18
</span></span><span class="line"><span class="cl">The key<span class="err">&#39;</span>s randomart image is:
</span></span><span class="line"><span class="cl">+---<span class="o">[</span>RSA 2048<span class="o">]</span>----+
</span></span><span class="line"><span class="cl"><span class="p">|</span>        .        <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>       <span class="o">=</span> .   .   <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>        B .o. +  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>       . oo.o+   <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>        S  ++ ..o<span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>       o ..+.A<span class="o">=</span><span class="nv">o</span><span class="o">=</span><span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>      o   +..B+<span class="o">=</span>+<span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>       .   <span class="nv">oo</span><span class="o">=</span>@o+<span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>           <span class="nv">o</span><span class="o">=</span><span class="nv">ss</span><span class="o">=</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl">+----<span class="o">[</span>SHA256<span class="o">]</span>-----+
</span></span></code></pre></div><p>一直回车确定，生成公私钥，保存在<code>~/.ssh</code>目录下。</p>
<blockquote>
<p>我在宿主机上生成的公私钥名称为，分别是<code>host2servera_id_rsa</code>,<code>host2servera_id_rsa.pub</code>方便我记忆。如果一直回车，那么生成的公私钥名称为<code>id_rsa</code>，<code>id_rsa.pub</code>。</p>
</blockquote>
<h1 id="发送公钥">发送公钥</h1>
<p>将公钥复制到服务器 ServerA 上，以 IP：<code>10.12.193.53</code> 为例。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">$ ssh-copy-id 10.12.193.53
</span></span><span class="line"><span class="cl"><span class="c1"># 输入密码</span>
</span></span><span class="line"><span class="cl">/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key<span class="o">(</span>s<span class="o">)</span>, to filter out any that are already installed
</span></span><span class="line"><span class="cl">/usr/bin/ssh-copy-id: INFO: <span class="m">1</span> key<span class="o">(</span>s<span class="o">)</span> remain to be installed -- <span class="k">if</span> you are prompted now it is to install the new keys
</span></span><span class="line"><span class="cl">user@10.12.193.53<span class="s1">&#39;s password: 
</span></span></span><span class="line"><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">Number of key(s) added: 1
</span></span></span><span class="line"><span class="cl"><span class="s1">
</span></span></span><span class="line"><span class="cl"><span class="s1">Now try logging into the machine, with:   &#34;ssh &#39;</span>10.12.193.53<span class="err">&#39;</span><span class="s2">&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">and check to make sure that only the key(s) you wanted were added.
</span></span></span></code></pre></div><p>默认是把 ServerA 的用户当做 user 进行登录。如果有确定的用户如<code>userA</code>，就使用<code>ssh-copy-id userA@10.12.193.53</code></p>
<p>然后就可以直接免密码登录了：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">ssh user@10.12.193.53
</span></span><span class="line"><span class="cl"><span class="c1"># 或者</span>
</span></span><span class="line"><span class="cl">ssh userA@10.12.193.53
</span></span></code></pre></div><p>如果还是需要输入密码，可能<code>ssh-agent</code>没有启动，执行<code>eval $(ssh-agent)</code>启动<code>ssh-agent</code>，然后再次登录即可。然后将私钥添加到<code>ssh-agent</code>中，执行<code>ssh-add ~/.ssh/host2servera_id_rsa</code>，然后再次登录即可。</p>
<h1 id="配置快捷登录">配置快捷登录</h1>
<p>即使免密登录，输入一长串 IP 也太麻烦了，能不能配置更简单的登录方式，比如给服务器起个名字如<code>ServerA</code>直接使用<code>ssh ServerA</code>就登录服务器，能。</p>
<p>打开<code>~/.ssh/config</code>配置如下内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Ini" data-lang="Ini"><span class="line"><span class="cl"><span class="na">Host ServerA</span>
</span></span><span class="line"><span class="cl">    <span class="na">HostName 10.12.193.53</span>
</span></span><span class="line"><span class="cl">    <span class="na">Port 22</span>
</span></span><span class="line"><span class="cl">    <span class="na">User userA</span>
</span></span><span class="line"><span class="cl">    <span class="na">IdentityFile ~/.ssh/host2servera_id_rsa</span>
</span></span></code></pre></div><p>然后就可以直接使用<code>ssh ServerA</code>登录了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>SSH 登录 OpenStack 实例</title>
      <link>https://lifeislife.cn/posts/ssh-%E7%99%BB%E5%BD%95-openstack-%E5%AE%9E%E4%BE%8B/</link>
      <pubDate>Wed, 28 Jun 2023 22:20:05 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ssh-%E7%99%BB%E5%BD%95-openstack-%E5%AE%9E%E4%BE%8B/</guid>
      <description>&lt;h1 id=&#34;基础配置&#34;&gt;基础配置&lt;/h1&gt;
&lt;p&gt;添加安全组规则，允许 Ping 和 SSH 访问虚拟机：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openstack security group rule create --proto icmp default
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@allone:~# openstack security group rule create --proto icmp default
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------------+---------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Field             &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Value                                                                                                                                                   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------------+-------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; created_at        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 2023-06-28T06:26:10Z                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; description       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                                                                                                                                                         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; direction         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ingress                                                                                                                                                 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ether_type        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; IPv4                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; id                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; fe9adfc3-dc42-4680-8ecd-ed5a667e1215                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; location          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;cloud&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;, project.domain_id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;, project.domain_name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Default&amp;#39;&lt;/span&gt;, project.id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;6396365541a74b6b8ea8812d1af05e70&amp;#39;&lt;/span&gt;, project.name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;region_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;zone&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; name              &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; None                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; port_range_max    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; None                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; port_range_min    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; None                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; project_id        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 6396365541a74b6b8ea8812d1af05e70                                                                                                                        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; protocol          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; icmp                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; remote_group_id   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; None                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; remote_ip_prefix  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 0.0.0.0/0                                                                                                                                               &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; revision_number   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;                                                                                                                                                       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; security_group_id &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; f10a3927-5e76-47b4-8691-4169348845ae                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tags              &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;                                                                                                                                                      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; updated_at        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 2023-06-28T06:26:10Z                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------------+--------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openstack security group rule create --proto tcp --dst-port &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt; default
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@allone:~# openstack security group rule  create --proto tcp --dst-port &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt; default
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------------+--------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Field             &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Value                                                                                                                                                   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------------+--------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; created_at        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 2023-06-28T06:26:15Z                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; description       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;                                                                                                                                                         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; direction         &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ingress                                                                                                                                                 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ether_type        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; IPv4                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; id                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; af699cf9-5fc0-45e2-a009-0bb7828e2d1a                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; location          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;cloud&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;, project.domain_id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;, project.domain_name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Default&amp;#39;&lt;/span&gt;, project.id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;6396365541a74b6b8ea8812d1af05e70&amp;#39;&lt;/span&gt;, project.name&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;region_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;, &lt;span class=&#34;nv&#34;&gt;zone&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; name              &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; None                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; port_range_max    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt;                                                                                                                                                      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; port_range_min    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt;                                                                                                                                                      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; project_id        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 6396365541a74b6b8ea8812d1af05e70                                                                                                                        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; protocol          &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tcp                                                                                                                                                     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; remote_group_id   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; None                                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; remote_ip_prefix  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 0.0.0.0/0                                                                                                                                               &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; revision_number   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;                                                                                                                                                       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; security_group_id &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; f10a3927-5e76-47b4-8691-4169348845ae                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tags              &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[]&lt;/span&gt;                                                                                                                                                      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; updated_at        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 2023-06-28T06:26:15Z                                                                                                                                    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------------+-----------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;命令行方式&#34;&gt;命令行方式&lt;/h1&gt;
&lt;h2 id=&#34;生成秘钥&#34;&gt;生成秘钥&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-keygen -q -N “”
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; 选项表示静默模式，即在生成密钥对的过程中不会输出任何提示信息或警告。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-N&lt;/code&gt; 选项后面可以跟一个密码作为参数。该密码将用于保护生成的私钥文件。如果不指定 &lt;code&gt;-N&lt;/code&gt; 参数，则私钥文件将不受密码保护。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;该命令会在&lt;code&gt;~/.ssh/&lt;/code&gt;目录中自动生成一对公私钥。默认私钥名称：id_rsa，默认公钥名称：id_rsa.pub&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openstack keypair create --public-key ~/.ssh/id_rsa.pub mykey
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;向 OpenStack 添加公钥，用于创建实例时选择：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@allone:~# openstack keypair create --public-key ~/.ssh/id_rsa.pub mykey
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Field       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Value                                           &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; fingerprint &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 11:36:75:e0:c3:98:4c:97:90:30:f5:69:e1:17:a9:4b &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; name        &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; mykey                                           &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; user_id     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 9027da91a2134825a421d78db11011d0                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+-------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openstack keypair list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@allone:~# openstack keypair list
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+---------------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Name                &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; Fingerprint                                     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+---------------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; mykey               &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 11:36:75:e0:c3:98:4c:97:90:30:f5:69:e1:17:a9:4b &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; ubuntu cloud server &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 67:b4:8a:64:83:4e:47:d0:7c:87:46:34:3b:03:e6:17 &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+---------------------+-------------------------------------------------+
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh ubuntu@10.0.2.111
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，&lt;code&gt;ubuntun&lt;/code&gt;是实例的用户名，&lt;code&gt;10.0.2.111&lt;/code&gt;是实例的 IP 地址。&lt;/p&gt;
&lt;h1 id=&#34;web-界面方式&#34;&gt;WEB 界面方式&lt;/h1&gt;
&lt;h2 id=&#34;创建密钥对&#34;&gt;创建密钥对&lt;/h2&gt;
&lt;p&gt;Project-Key Pairs-Create Keypairs&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-21-d58cbf697d71c5fff58fda7a8145ceae-20230628175315-733a20.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-21-d58cbf697d71c5fff58fda7a8145ceae-20230628175315-733a20.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;为密钥对起个名字：sshkey，并选择一个类型：SSH Key&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-37-56223c56c675b84ea1d375399db38175-20230628175333-06df78.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-37-56223c56c675b84ea1d375399db38175-20230628175333-06df78.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;点击创建后会弹出下载私钥的窗口，这时候需要将私钥下载到本地。并将他移动到 ssh 目录下方便管理。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 切换root用户，因为我们一直都是用root用户操作的OpenStack&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo su
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv sshkey.pem ~/.ssh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-54-d452e4565933506f89744f60f01d7956-20230628175349-ffaa20.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-54-d452e4565933506f89744f60f01d7956-20230628175349-ffaa20.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;使用公钥创建实例&#34;&gt;使用公钥创建实例&lt;/h2&gt;
&lt;p&gt;Project-Instances-Launch Instance&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-54-08-24889d77a26052dab99f758c54ce9483-20230628175403-9acef3.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-54-08-24889d77a26052dab99f758c54ce9483-20230628175403-9acef3.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;在 Key Pair 中选择刚刚创建的 sshkey。这里实际就是将创建的密钥对中的公钥放到了我们的实例中，这样我们就可以拿着本地的私钥去访问实例。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-54-19-5ac37e246ffbd6007356092eac047d6b-20230628175415-7f105e.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-54-19-5ac37e246ffbd6007356092eac047d6b-20230628175415-7f105e.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;登录实例&#34;&gt;登录实例&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh -i ~/.ssh/sshkey.pem  ubuntun@10.0.2.111
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中&lt;code&gt;~/.ssh/sshkey.pem&lt;/code&gt;是我们下载的私钥文件，&lt;code&gt;ubuntun&lt;/code&gt;是实例的用户名，&lt;code&gt;10.0.2.111&lt;/code&gt;是实例的 IP 地址。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="基础配置">基础配置</h1>
<p>添加安全组规则，允许 Ping 和 SSH 访问虚拟机：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">openstack security group rule create --proto icmp default
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@allone:~# openstack security group rule create --proto icmp default
</span></span><span class="line"><span class="cl">+-------------------+---------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> Field             <span class="p">|</span> Value                                                                                                                                                   <span class="p">|</span>
</span></span><span class="line"><span class="cl">+-------------------+-------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> created_at        <span class="p">|</span> 2023-06-28T06:26:10Z                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> description       <span class="p">|</span>                                                                                                                                                         <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> direction         <span class="p">|</span> ingress                                                                                                                                                 <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> ether_type        <span class="p">|</span> IPv4                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> id                <span class="p">|</span> fe9adfc3-dc42-4680-8ecd-ed5a667e1215                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> location          <span class="p">|</span> <span class="nv">cloud</span><span class="o">=</span><span class="s1">&#39;&#39;</span>, project.domain_id<span class="o">=</span>, project.domain_name<span class="o">=</span><span class="s1">&#39;Default&#39;</span>, project.id<span class="o">=</span><span class="s1">&#39;6396365541a74b6b8ea8812d1af05e70&#39;</span>, project.name<span class="o">=</span><span class="s1">&#39;admin&#39;</span>, <span class="nv">region_name</span><span class="o">=</span><span class="s1">&#39;&#39;</span>, <span class="nv">zone</span><span class="o">=</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> name              <span class="p">|</span> None                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> port_range_max    <span class="p">|</span> None                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> port_range_min    <span class="p">|</span> None                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> project_id        <span class="p">|</span> 6396365541a74b6b8ea8812d1af05e70                                                                                                                        <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> protocol          <span class="p">|</span> icmp                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> remote_group_id   <span class="p">|</span> None                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> remote_ip_prefix  <span class="p">|</span> 0.0.0.0/0                                                                                                                                               <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> revision_number   <span class="p">|</span> <span class="m">0</span>                                                                                                                                                       <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> security_group_id <span class="p">|</span> f10a3927-5e76-47b4-8691-4169348845ae                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> tags              <span class="p">|</span> <span class="o">[]</span>                                                                                                                                                      <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> updated_at        <span class="p">|</span> 2023-06-28T06:26:10Z                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl">+-------------------+--------------------------------+
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">openstack security group rule create --proto tcp --dst-port <span class="m">22</span> default
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@allone:~# openstack security group rule  create --proto tcp --dst-port <span class="m">22</span> default
</span></span><span class="line"><span class="cl">+-------------------+--------------------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> Field             <span class="p">|</span> Value                                                                                                                                                   <span class="p">|</span>
</span></span><span class="line"><span class="cl">+-------------------+--------------------------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> created_at        <span class="p">|</span> 2023-06-28T06:26:15Z                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> description       <span class="p">|</span>                                                                                                                                                         <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> direction         <span class="p">|</span> ingress                                                                                                                                                 <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> ether_type        <span class="p">|</span> IPv4                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> id                <span class="p">|</span> af699cf9-5fc0-45e2-a009-0bb7828e2d1a                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> location          <span class="p">|</span> <span class="nv">cloud</span><span class="o">=</span><span class="s1">&#39;&#39;</span>, project.domain_id<span class="o">=</span>, project.domain_name<span class="o">=</span><span class="s1">&#39;Default&#39;</span>, project.id<span class="o">=</span><span class="s1">&#39;6396365541a74b6b8ea8812d1af05e70&#39;</span>, project.name<span class="o">=</span><span class="s1">&#39;admin&#39;</span>, <span class="nv">region_name</span><span class="o">=</span><span class="s1">&#39;&#39;</span>, <span class="nv">zone</span><span class="o">=</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> name              <span class="p">|</span> None                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> port_range_max    <span class="p">|</span> <span class="m">22</span>                                                                                                                                                      <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> port_range_min    <span class="p">|</span> <span class="m">22</span>                                                                                                                                                      <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> project_id        <span class="p">|</span> 6396365541a74b6b8ea8812d1af05e70                                                                                                                        <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> protocol          <span class="p">|</span> tcp                                                                                                                                                     <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> remote_group_id   <span class="p">|</span> None                                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> remote_ip_prefix  <span class="p">|</span> 0.0.0.0/0                                                                                                                                               <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> revision_number   <span class="p">|</span> <span class="m">0</span>                                                                                                                                                       <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> security_group_id <span class="p">|</span> f10a3927-5e76-47b4-8691-4169348845ae                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> tags              <span class="p">|</span> <span class="o">[]</span>                                                                                                                                                      <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> updated_at        <span class="p">|</span> 2023-06-28T06:26:15Z                                                                                                                                    <span class="p">|</span>
</span></span><span class="line"><span class="cl">+-------------------+-----------------+
</span></span></code></pre></div><h1 id="命令行方式">命令行方式</h1>
<h2 id="生成秘钥">生成秘钥</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ssh-keygen -q -N “”
</span></span></code></pre></div><blockquote>
<ul>
<li><code>-q</code> 选项表示静默模式，即在生成密钥对的过程中不会输出任何提示信息或警告。</li>
<li><code>-N</code> 选项后面可以跟一个密码作为参数。该密码将用于保护生成的私钥文件。如果不指定 <code>-N</code> 参数，则私钥文件将不受密码保护。</li>
</ul>
</blockquote>
<p>该命令会在<code>~/.ssh/</code>目录中自动生成一对公私钥。默认私钥名称：id_rsa，默认公钥名称：id_rsa.pub</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">openstack keypair create --public-key ~/.ssh/id_rsa.pub mykey
</span></span></code></pre></div><p>向 OpenStack 添加公钥，用于创建实例时选择：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@allone:~# openstack keypair create --public-key ~/.ssh/id_rsa.pub mykey
</span></span><span class="line"><span class="cl">+-------------+-------------------------------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> Field       <span class="p">|</span> Value                                           <span class="p">|</span>
</span></span><span class="line"><span class="cl">+-------------+-------------------------------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> fingerprint <span class="p">|</span> 11:36:75:e0:c3:98:4c:97:90:30:f5:69:e1:17:a9:4b <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> name        <span class="p">|</span> mykey                                           <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> user_id     <span class="p">|</span> 9027da91a2134825a421d78db11011d0                <span class="p">|</span>
</span></span><span class="line"><span class="cl">+-------------+-------------------------------------------------+
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">openstack keypair list
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root@allone:~# openstack keypair list
</span></span><span class="line"><span class="cl">+---------------------+-------------------------------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> Name                <span class="p">|</span> Fingerprint                                     <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---------------------+-------------------------------------------------+
</span></span><span class="line"><span class="cl"><span class="p">|</span> mykey               <span class="p">|</span> 11:36:75:e0:c3:98:4c:97:90:30:f5:69:e1:17:a9:4b <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> ubuntu cloud server <span class="p">|</span> 67:b4:8a:64:83:4e:47:d0:7c:87:46:34:3b:03:e6:17 <span class="p">|</span>
</span></span><span class="line"><span class="cl">+---------------------+-------------------------------------------------+
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ssh ubuntu@10.0.2.111
</span></span></code></pre></div><p>其中，<code>ubuntun</code>是实例的用户名，<code>10.0.2.111</code>是实例的 IP 地址。</p>
<h1 id="web-界面方式">WEB 界面方式</h1>
<h2 id="创建密钥对">创建密钥对</h2>
<p>Project-Key Pairs-Create Keypairs</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-21-d58cbf697d71c5fff58fda7a8145ceae-20230628175315-733a20.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-21-d58cbf697d71c5fff58fda7a8145ceae-20230628175315-733a20.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>为密钥对起个名字：sshkey，并选择一个类型：SSH Key</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-37-56223c56c675b84ea1d375399db38175-20230628175333-06df78.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-37-56223c56c675b84ea1d375399db38175-20230628175333-06df78.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>点击创建后会弹出下载私钥的窗口，这时候需要将私钥下载到本地。并将他移动到 ssh 目录下方便管理。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 切换root用户，因为我们一直都是用root用户操作的OpenStack</span>
</span></span><span class="line"><span class="cl">sudo su
</span></span><span class="line"><span class="cl">mv sshkey.pem ~/.ssh
</span></span></code></pre></div><p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-54-d452e4565933506f89744f60f01d7956-20230628175349-ffaa20.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-53-54-d452e4565933506f89744f60f01d7956-20230628175349-ffaa20.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="使用公钥创建实例">使用公钥创建实例</h2>
<p>Project-Instances-Launch Instance</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-54-08-24889d77a26052dab99f758c54ce9483-20230628175403-9acef3.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-54-08-24889d77a26052dab99f758c54ce9483-20230628175403-9acef3.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>在 Key Pair 中选择刚刚创建的 sshkey。这里实际就是将创建的密钥对中的公钥放到了我们的实例中，这样我们就可以拿着本地的私钥去访问实例。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-54-19-5ac37e246ffbd6007356092eac047d6b-20230628175415-7f105e.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/17-54-19-5ac37e246ffbd6007356092eac047d6b-20230628175415-7f105e.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="登录实例">登录实例</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ssh -i ~/.ssh/sshkey.pem  ubuntun@10.0.2.111
</span></span></code></pre></div><p>其中<code>~/.ssh/sshkey.pem</code>是我们下载的私钥文件，<code>ubuntun</code>是实例的用户名，<code>10.0.2.111</code>是实例的 IP 地址。</p>
]]></content:encoded>
    </item>
    <item>
      <title>VirtualBox Ubuntu 无法联网</title>
      <link>https://lifeislife.cn/posts/virtualbox-ubuntu%E6%97%A0%E6%B3%95%E8%81%94%E7%BD%91/</link>
      <pubDate>Mon, 26 Jun 2023 22:38:02 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/virtualbox-ubuntu%E6%97%A0%E6%B3%95%E8%81%94%E7%BD%91/</guid>
      <description>&lt;h1 id=&#34;解决方案&#34;&gt;解决方案&lt;/h1&gt;
&lt;p&gt;VirtualBox Ubuntu 无法联网，重启后可以联网但是几分钟后断开网络。笔者的情况是因为 NetworkManager 自动修改了网络配置导致无法联网，具体现象是开机后网卡信息如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;user@allone:~$ ifconfig
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;brq64ff9b38-fa: &lt;span class=&#34;nv&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4163&amp;lt;UP,BROADCAST,RUNNING,MULTICAST&amp;gt;  mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ether ce:29:de:12:35:06  txqueuelen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Ethernet&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        RX packets &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  bytes &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0.0 B&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        RX errors &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  dropped &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  overruns &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  frame &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        TX packets &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  bytes &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0.0 B&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        TX errors &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  dropped &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; overruns &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  carrier &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  collisions &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;enp0s3: &lt;span class=&#34;nv&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4163&amp;lt;UP,BROADCAST,RUNNING,MULTICAST&amp;gt;  mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        inet6 fe80::2e8f:2be6:3752:dec4  prefixlen &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt;  scopeid 0x20&amp;lt;link&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ether 08:00:27:18:31:21  txqueuelen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Ethernet&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        RX packets &lt;span class=&#34;m&#34;&gt;947&lt;/span&gt;  bytes &lt;span class=&#34;m&#34;&gt;584483&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;584.4 KB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        RX errors &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  dropped &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  overruns &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  frame &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        TX packets &lt;span class=&#34;m&#34;&gt;800&lt;/span&gt;  bytes &lt;span class=&#34;m&#34;&gt;116611&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;116.6 KB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        TX errors &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  dropped &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; overruns &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  carrier &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  collisions &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时网络可以正常使用，经过一两分钟后网络信息如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;user@allone:~$ ifconfig
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;brq64ff9b38-fa: &lt;span class=&#34;nv&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4163&amp;lt;UP,BROADCAST,RUNNING,MULTICAST&amp;gt;  mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ether ce:29:de:12:35:06  txqueuelen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Ethernet&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        RX packets &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  bytes &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0.0 B&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        RX errors &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  dropped &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  overruns &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  frame &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        TX packets &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  bytes &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;0.0 B&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        TX errors &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  dropped &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; overruns &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  carrier &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  collisions &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;enp0s3: &lt;span class=&#34;nv&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4163&amp;lt;UP,BROADCAST,RUNNING,MULTICAST&amp;gt;  mtu &lt;span class=&#34;m&#34;&gt;1500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        inet6 fe80::2e8f:2be6:3752:dec4  prefixlen &lt;span class=&#34;m&#34;&gt;64&lt;/span&gt;  scopeid 0x20&amp;lt;link&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ether 08:00:27:18:31:21  txqueuelen &lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Ethernet&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        RX packets &lt;span class=&#34;m&#34;&gt;947&lt;/span&gt;  bytes &lt;span class=&#34;m&#34;&gt;584483&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;584.4 KB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        RX errors &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  dropped &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  overruns &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  frame &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        TX packets &lt;span class=&#34;m&#34;&gt;800&lt;/span&gt;  bytes &lt;span class=&#34;m&#34;&gt;116611&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;116.6 KB&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        TX errors &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  dropped &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; overruns &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  carrier &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  collisions &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也就是默认虚拟网卡的 IP 地址丢失，而不知名网卡 brq64ff9b38-fa 却拥有了 IP，此时网络不可用。如果有类似情况，可以使用以下方式尝试解决，如果是其他问题。请酌情参考。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;关闭 NetworkManager&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl stop NetworkManager
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl disable NetworkManager
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl mask NetworkManager
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;开启 systemd-networkd&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl unmask systemd-networkd.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl &lt;span class=&#34;nb&#34;&gt;enable&lt;/span&gt; systemd-networkd.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl start systemd-networkd.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;配置 Netplan&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;编辑/etc/netplan/01-network-manager-all.yaml&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;network:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    version: &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    renderer: networkd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ethernets:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       enp0s3:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           dhcp4: yes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           dhcp6: yes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           addresses: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;10.0.2.15/23&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           nameservers:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               addresses: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;8.8.8.8, 8.8.4.4&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           optional: &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 enp0s3 为网卡名称，addresses 为网卡对应的 IP，均可以通过 ifconfig 查询。&lt;/p&gt;
&lt;p&gt;以下是一些背景知识，以及问题回溯有兴趣可以继续阅读。&lt;/p&gt;
&lt;h1 id=&#34;背景知识&#34;&gt;背景知识&lt;/h1&gt;
&lt;h2 id=&#34;networkmanager-与-systemd-networked&#34;&gt;NetworkManager 与 systemd-networked&lt;/h2&gt;
&lt;p&gt;NetworkManager 是一项后端服务，用于控制 Ubuntu 操作系统上的网络接口。NetworkManager 的替代方法是 systemd-networked，这两者只能使用一个。在 Ubuntu 桌面上，NetworkManager 是通过图形用户界面管理网络界面的默认服务。因此，如果要通过 GUI 配置 IP 地址，则应启用 NetworkManager。如果用的是无桌面的 Server 版，就可以使用 systemd-networked 来管理网络。&lt;/p&gt;
&lt;p&gt;这两种方式都可以通过配置 netplan，即/etc/netplan/01-network-manager-all.yaml 来管理网络，但是在 renderer 属性中配置有所不同，使用 NetworkManager 时配置如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;network:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    version: &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    renderer: NetworkManager
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而使用 systemd-networked 时，配置如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;network:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    version: &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    renderer: networkd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;有时无法联网可能是因为配置与实际使用的网络管理方式不匹配导致的。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="解决方案">解决方案</h1>
<p>VirtualBox Ubuntu 无法联网，重启后可以联网但是几分钟后断开网络。笔者的情况是因为 NetworkManager 自动修改了网络配置导致无法联网，具体现象是开机后网卡信息如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">user@allone:~$ ifconfig
</span></span><span class="line"><span class="cl">brq64ff9b38-fa: <span class="nv">flags</span><span class="o">=</span>4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu <span class="m">1500</span>
</span></span><span class="line"><span class="cl">        ether ce:29:de:12:35:06  txqueuelen <span class="m">1000</span>  <span class="o">(</span>Ethernet<span class="o">)</span>
</span></span><span class="line"><span class="cl">        RX packets <span class="m">0</span>  bytes <span class="m">0</span> <span class="o">(</span>0.0 B<span class="o">)</span>
</span></span><span class="line"><span class="cl">        RX errors <span class="m">0</span>  dropped <span class="m">0</span>  overruns <span class="m">0</span>  frame <span class="m">0</span>
</span></span><span class="line"><span class="cl">        TX packets <span class="m">0</span>  bytes <span class="m">0</span> <span class="o">(</span>0.0 B<span class="o">)</span>
</span></span><span class="line"><span class="cl">        TX errors <span class="m">0</span>  dropped <span class="m">0</span> overruns <span class="m">0</span>  carrier <span class="m">0</span>  collisions <span class="m">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">enp0s3: <span class="nv">flags</span><span class="o">=</span>4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu <span class="m">1500</span>
</span></span><span class="line"><span class="cl">        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
</span></span><span class="line"><span class="cl">        inet6 fe80::2e8f:2be6:3752:dec4  prefixlen <span class="m">64</span>  scopeid 0x20&lt;link&gt;
</span></span><span class="line"><span class="cl">        ether 08:00:27:18:31:21  txqueuelen <span class="m">1000</span>  <span class="o">(</span>Ethernet<span class="o">)</span>
</span></span><span class="line"><span class="cl">        RX packets <span class="m">947</span>  bytes <span class="m">584483</span> <span class="o">(</span>584.4 KB<span class="o">)</span>
</span></span><span class="line"><span class="cl">        RX errors <span class="m">0</span>  dropped <span class="m">0</span>  overruns <span class="m">0</span>  frame <span class="m">0</span>
</span></span><span class="line"><span class="cl">        TX packets <span class="m">800</span>  bytes <span class="m">116611</span> <span class="o">(</span>116.6 KB<span class="o">)</span>
</span></span><span class="line"><span class="cl">        TX errors <span class="m">0</span>  dropped <span class="m">0</span> overruns <span class="m">0</span>  carrier <span class="m">0</span>  collisions <span class="m">0</span>
</span></span></code></pre></div><p>此时网络可以正常使用，经过一两分钟后网络信息如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">user@allone:~$ ifconfig
</span></span><span class="line"><span class="cl">brq64ff9b38-fa: <span class="nv">flags</span><span class="o">=</span>4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu <span class="m">1500</span>
</span></span><span class="line"><span class="cl">        inet 10.0.2.15  netmask 255.255.255.0  broadcast 10.0.2.255
</span></span><span class="line"><span class="cl">        ether ce:29:de:12:35:06  txqueuelen <span class="m">1000</span>  <span class="o">(</span>Ethernet<span class="o">)</span>
</span></span><span class="line"><span class="cl">        RX packets <span class="m">0</span>  bytes <span class="m">0</span> <span class="o">(</span>0.0 B<span class="o">)</span>
</span></span><span class="line"><span class="cl">        RX errors <span class="m">0</span>  dropped <span class="m">0</span>  overruns <span class="m">0</span>  frame <span class="m">0</span>
</span></span><span class="line"><span class="cl">        TX packets <span class="m">0</span>  bytes <span class="m">0</span> <span class="o">(</span>0.0 B<span class="o">)</span>
</span></span><span class="line"><span class="cl">        TX errors <span class="m">0</span>  dropped <span class="m">0</span> overruns <span class="m">0</span>  carrier <span class="m">0</span>  collisions <span class="m">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">enp0s3: <span class="nv">flags</span><span class="o">=</span>4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu <span class="m">1500</span>
</span></span><span class="line"><span class="cl">        inet6 fe80::2e8f:2be6:3752:dec4  prefixlen <span class="m">64</span>  scopeid 0x20&lt;link&gt;
</span></span><span class="line"><span class="cl">        ether 08:00:27:18:31:21  txqueuelen <span class="m">1000</span>  <span class="o">(</span>Ethernet<span class="o">)</span>
</span></span><span class="line"><span class="cl">        RX packets <span class="m">947</span>  bytes <span class="m">584483</span> <span class="o">(</span>584.4 KB<span class="o">)</span>
</span></span><span class="line"><span class="cl">        RX errors <span class="m">0</span>  dropped <span class="m">0</span>  overruns <span class="m">0</span>  frame <span class="m">0</span>
</span></span><span class="line"><span class="cl">        TX packets <span class="m">800</span>  bytes <span class="m">116611</span> <span class="o">(</span>116.6 KB<span class="o">)</span>
</span></span><span class="line"><span class="cl">        TX errors <span class="m">0</span>  dropped <span class="m">0</span> overruns <span class="m">0</span>  carrier <span class="m">0</span>  collisions <span class="m">0</span>
</span></span></code></pre></div><p>也就是默认虚拟网卡的 IP 地址丢失，而不知名网卡 brq64ff9b38-fa 却拥有了 IP，此时网络不可用。如果有类似情况，可以使用以下方式尝试解决，如果是其他问题。请酌情参考。</p>
<ol>
<li>关闭 NetworkManager</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo systemctl stop NetworkManager
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo systemctl disable NetworkManager
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo systemctl mask NetworkManager
</span></span></code></pre></div><ol start="2">
<li>开启 systemd-networkd</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo systemctl unmask systemd-networkd.service
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo systemctl <span class="nb">enable</span> systemd-networkd.service
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo systemctl start systemd-networkd.service
</span></span></code></pre></div><ol start="3">
<li>配置 Netplan</li>
</ol>
<p>编辑/etc/netplan/01-network-manager-all.yaml</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">network:
</span></span><span class="line"><span class="cl">    version: <span class="m">2</span>
</span></span><span class="line"><span class="cl">    renderer: networkd
</span></span><span class="line"><span class="cl">    ethernets:
</span></span><span class="line"><span class="cl">       enp0s3:
</span></span><span class="line"><span class="cl">           dhcp4: yes
</span></span><span class="line"><span class="cl">           dhcp6: yes
</span></span><span class="line"><span class="cl">           addresses: <span class="o">[</span>10.0.2.15/23<span class="o">]</span>
</span></span><span class="line"><span class="cl">           nameservers:
</span></span><span class="line"><span class="cl">               addresses: <span class="o">[</span>8.8.8.8, 8.8.4.4<span class="o">]</span>
</span></span><span class="line"><span class="cl">           optional: <span class="nb">true</span>
</span></span></code></pre></div><p>其中 enp0s3 为网卡名称，addresses 为网卡对应的 IP，均可以通过 ifconfig 查询。</p>
<p>以下是一些背景知识，以及问题回溯有兴趣可以继续阅读。</p>
<h1 id="背景知识">背景知识</h1>
<h2 id="networkmanager-与-systemd-networked">NetworkManager 与 systemd-networked</h2>
<p>NetworkManager 是一项后端服务，用于控制 Ubuntu 操作系统上的网络接口。NetworkManager 的替代方法是 systemd-networked，这两者只能使用一个。在 Ubuntu 桌面上，NetworkManager 是通过图形用户界面管理网络界面的默认服务。因此，如果要通过 GUI 配置 IP 地址，则应启用 NetworkManager。如果用的是无桌面的 Server 版，就可以使用 systemd-networked 来管理网络。</p>
<p>这两种方式都可以通过配置 netplan，即/etc/netplan/01-network-manager-all.yaml 来管理网络，但是在 renderer 属性中配置有所不同，使用 NetworkManager 时配置如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">network:
</span></span><span class="line"><span class="cl">    version: <span class="m">2</span>
</span></span><span class="line"><span class="cl">    renderer: NetworkManager
</span></span></code></pre></div><p>而使用 systemd-networked 时，配置如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">network:
</span></span><span class="line"><span class="cl">    version: <span class="m">2</span>
</span></span><span class="line"><span class="cl">    renderer: networkd
</span></span></code></pre></div><p>有时无法联网可能是因为配置与实际使用的网络管理方式不匹配导致的。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Ubuntu 18.04 安装Clang/LLVM 11</title>
      <link>https://lifeislife.cn/posts/ubuntu-18-04-%E5%AE%89%E8%A3%85clang-llvm-11/</link>
      <pubDate>Sat, 24 Dec 2022 15:53:22 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ubuntu-18-04-%E5%AE%89%E8%A3%85clang-llvm-11/</guid>
      <description>&lt;h2 id=&#34;从-apt-安装&#34;&gt;从 APT 安装&lt;/h2&gt;
&lt;p&gt;Install the GPG Key for &lt;code&gt;https://apt.llvm.org/&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo apt-key add -
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the repo for Clang 11 &lt;code&gt;stable-old&lt;/code&gt; for Ubuntu 18.04 Bionic&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee -a /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Install practically everything (except &lt;code&gt;python-clang-11&lt;/code&gt; which for some reason doesn&amp;rsquo;t work)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install libllvm-11-ocaml-dev libllvm11 llvm-11 llvm-11-dev llvm-11-doc llvm-11-examples llvm-11-runtime &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;clang-11 clang-tools-11 clang-11-doc libclang-common-11-dev libclang-11-dev libclang1-11 clang-format-11 clangd-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;libfuzzer-11-dev lldb-11 lld-11 libc++-11-dev libc++abi-11-dev libomp-11-dev -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Make Clang 11 and everything related to it defaults&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-alternatives &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --install /usr/lib/llvm              llvm             /usr/lib/llvm-11         &lt;span class=&#34;m&#34;&gt;50&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-config       llvm-config      /usr/bin/llvm-config-11  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-ar           llvm-ar          /usr/bin/llvm-ar-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-as           llvm-as          /usr/bin/llvm-as-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-bcanalyzer   llvm-bcanalyzer  /usr/bin/llvm-bcanalyzer-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-cov          llvm-cov         /usr/bin/llvm-cov-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-diff         llvm-diff        /usr/bin/llvm-diff-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-dis          llvm-dis         /usr/bin/llvm-dis-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-dwarfdump    llvm-dwarfdump   /usr/bin/llvm-dwarfdump-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-extract      llvm-extract     /usr/bin/llvm-extract-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-link         llvm-link        /usr/bin/llvm-link-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-mc           llvm-mc          /usr/bin/llvm-mc-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-mcmarkup     llvm-mcmarkup    /usr/bin/llvm-mcmarkup-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-nm           llvm-nm          /usr/bin/llvm-nm-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-objdump      llvm-objdump     /usr/bin/llvm-objdump-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-ranlib       llvm-ranlib      /usr/bin/llvm-ranlib-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-readobj      llvm-readobj     /usr/bin/llvm-readobj-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-rtdyld       llvm-rtdyld      /usr/bin/llvm-rtdyld-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-size         llvm-size        /usr/bin/llvm-size-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-stress       llvm-stress      /usr/bin/llvm-stress-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-symbolizer   llvm-symbolizer  /usr/bin/llvm-symbolizer-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/llvm-tblgen       llvm-tblgen      /usr/bin/llvm-tblgen-11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-alternatives &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --install /usr/bin/clang                 clang                  /usr/bin/clang-11    &lt;span class=&#34;m&#34;&gt;50&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang++               clang++                /usr/bin/clang++-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/lld                   lld                    /usr/bin/lld-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-format          clang-format           /usr/bin/clang-format-11  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-tidy            clang-tidy             /usr/bin/clang-tidy-11  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-tidy-diff.py    clang-tidy-diff.py     /usr/bin/clang-tidy-diff-11.py &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-include-fixer   clang-include-fixer    /usr/bin/clang-include-fixer-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-offload-bundler clang-offload-bundler  /usr/bin/clang-offload-bundler-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clangd                clangd                 /usr/bin/clangd-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-check           clang-check            /usr/bin/clang-check-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/scan-view             scan-view              /usr/bin/scan-view-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-apply-replacements clang-apply-replacements /usr/bin/clang-apply-replacements-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-query           clang-query            /usr/bin/clang-query-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/modularize            modularize             /usr/bin/modularize-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/sancov                sancov                 /usr/bin/sancov-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/c-index-test          c-index-test           /usr/bin/c-index-test-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-reorder-fields  clang-reorder-fields   /usr/bin/clang-reorder-fields-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-change-namespace clang-change-namespace  /usr/bin/clang-change-namespace-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-import-test     clang-import-test      /usr/bin/clang-import-test-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/scan-build            scan-build             /usr/bin/scan-build-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/scan-build-py         scan-build-py          /usr/bin/scan-build-py-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-cl              clang-cl               /usr/bin/clang-cl-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/clang-rename          clang-rename           /usr/bin/clang-rename-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/find-all-symbols      find-all-symbols       /usr/bin/find-all-symbols-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/lldb                  lldb                   /usr/bin/lldb-11 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --slave   /usr/bin/lldb-server           lldb-server            /usr/bin/lldb-server-11
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;installing-cmake&#34;&gt;Installing CMake&lt;/h2&gt;
&lt;p&gt;Install Kitware&amp;rsquo;s GPG Key&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2&amp;gt;/dev/null &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; gpg --dearmor - &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee /etc/apt/trusted.gpg.d/kitware.gpg &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add repository&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;deb https://apt.kitware.com/ubuntu/ bionic main&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee -a /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Install this optional package so you don&amp;rsquo;t have to mess with GPG keys anymore&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install kitware-archive-keyring
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo rm /etc/apt/trusted.gpg.d/kitware.gpg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now upgrade &lt;code&gt;cmake&lt;/code&gt; if you already have it installed with &lt;code&gt;sudo apt-get upgrade -y&lt;/code&gt; or just install it using &lt;code&gt;sudo apt-get install cmake -y&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;使用源码安装&#34;&gt;使用源码安装&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 更新软件包列表&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 安装必要的依赖包&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install build-essential cmake python3-dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 下载 Clang/LLVM 11 的源代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/llvm-11.0.0.src.tar.xz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 解压源代码文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar xvf llvm-11.0.0.src.tar.xz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 进入解压后的目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; llvm-11.0.0.src
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 创建一个新的目录，用于存放 Clang/LLVM 编译的结果&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 使用 cmake 编译 Clang/LLVM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cmake ..
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 编译 Clang/LLVM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 安装 Clang/LLVM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo make install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="从-apt-安装">从 APT 安装</h2>
<p>Install the GPG Key for <code>https://apt.llvm.org/</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key <span class="p">|</span> sudo apt-key add -
</span></span></code></pre></div><p>Add the repo for Clang 11 <code>stable-old</code> for Ubuntu 18.04 Bionic</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main&#34;</span> <span class="p">|</span> sudo tee -a /etc/apt/sources.list
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span></code></pre></div><p>Install practically everything (except <code>python-clang-11</code> which for some reason doesn&rsquo;t work)</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo apt-get install libllvm-11-ocaml-dev libllvm11 llvm-11 llvm-11-dev llvm-11-doc llvm-11-examples llvm-11-runtime <span class="se">\
</span></span></span><span class="line"><span class="cl">clang-11 clang-tools-11 clang-11-doc libclang-common-11-dev libclang-11-dev libclang1-11 clang-format-11 clangd-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">libfuzzer-11-dev lldb-11 lld-11 libc++-11-dev libc++abi-11-dev libomp-11-dev -y
</span></span></code></pre></div><p>Make Clang 11 and everything related to it defaults</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo update-alternatives <span class="se">\
</span></span></span><span class="line"><span class="cl">  --install /usr/lib/llvm              llvm             /usr/lib/llvm-11         <span class="m">50</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-config       llvm-config      /usr/bin/llvm-config-11  <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-ar           llvm-ar          /usr/bin/llvm-ar-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-as           llvm-as          /usr/bin/llvm-as-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-bcanalyzer   llvm-bcanalyzer  /usr/bin/llvm-bcanalyzer-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-cov          llvm-cov         /usr/bin/llvm-cov-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-diff         llvm-diff        /usr/bin/llvm-diff-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-dis          llvm-dis         /usr/bin/llvm-dis-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-dwarfdump    llvm-dwarfdump   /usr/bin/llvm-dwarfdump-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-extract      llvm-extract     /usr/bin/llvm-extract-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-link         llvm-link        /usr/bin/llvm-link-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-mc           llvm-mc          /usr/bin/llvm-mc-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-mcmarkup     llvm-mcmarkup    /usr/bin/llvm-mcmarkup-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-nm           llvm-nm          /usr/bin/llvm-nm-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-objdump      llvm-objdump     /usr/bin/llvm-objdump-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-ranlib       llvm-ranlib      /usr/bin/llvm-ranlib-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-readobj      llvm-readobj     /usr/bin/llvm-readobj-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-rtdyld       llvm-rtdyld      /usr/bin/llvm-rtdyld-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-size         llvm-size        /usr/bin/llvm-size-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-stress       llvm-stress      /usr/bin/llvm-stress-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-symbolizer   llvm-symbolizer  /usr/bin/llvm-symbolizer-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/llvm-tblgen       llvm-tblgen      /usr/bin/llvm-tblgen-11
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sudo update-alternatives <span class="se">\
</span></span></span><span class="line"><span class="cl">  --install /usr/bin/clang                 clang                  /usr/bin/clang-11    <span class="m">50</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang++               clang++                /usr/bin/clang++-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/lld                   lld                    /usr/bin/lld-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-format          clang-format           /usr/bin/clang-format-11  <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-tidy            clang-tidy             /usr/bin/clang-tidy-11  <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-tidy-diff.py    clang-tidy-diff.py     /usr/bin/clang-tidy-diff-11.py <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-include-fixer   clang-include-fixer    /usr/bin/clang-include-fixer-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-offload-bundler clang-offload-bundler  /usr/bin/clang-offload-bundler-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clangd                clangd                 /usr/bin/clangd-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-check           clang-check            /usr/bin/clang-check-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/scan-view             scan-view              /usr/bin/scan-view-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-apply-replacements clang-apply-replacements /usr/bin/clang-apply-replacements-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-query           clang-query            /usr/bin/clang-query-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/modularize            modularize             /usr/bin/modularize-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/sancov                sancov                 /usr/bin/sancov-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/c-index-test          c-index-test           /usr/bin/c-index-test-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-reorder-fields  clang-reorder-fields   /usr/bin/clang-reorder-fields-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-change-namespace clang-change-namespace  /usr/bin/clang-change-namespace-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-import-test     clang-import-test      /usr/bin/clang-import-test-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/scan-build            scan-build             /usr/bin/scan-build-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/scan-build-py         scan-build-py          /usr/bin/scan-build-py-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-cl              clang-cl               /usr/bin/clang-cl-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/clang-rename          clang-rename           /usr/bin/clang-rename-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/find-all-symbols      find-all-symbols       /usr/bin/find-all-symbols-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/lldb                  lldb                   /usr/bin/lldb-11 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --slave   /usr/bin/lldb-server           lldb-server            /usr/bin/lldb-server-11
</span></span></code></pre></div><h2 id="installing-cmake">Installing CMake</h2>
<p>Install Kitware&rsquo;s GPG Key</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2&gt;/dev/null <span class="p">|</span> gpg --dearmor - <span class="p">|</span> sudo tee /etc/apt/trusted.gpg.d/kitware.gpg &gt;/dev/null
</span></span></code></pre></div><p>Add repository</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;deb https://apt.kitware.com/ubuntu/ bionic main&#34;</span> <span class="p">|</span> sudo tee -a /etc/apt/sources.list
</span></span><span class="line"><span class="cl">sudo apt-get update
</span></span></code></pre></div><p>Install this optional package so you don&rsquo;t have to mess with GPG keys anymore</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo apt-get install kitware-archive-keyring
</span></span><span class="line"><span class="cl">sudo rm /etc/apt/trusted.gpg.d/kitware.gpg
</span></span></code></pre></div><p>Now upgrade <code>cmake</code> if you already have it installed with <code>sudo apt-get upgrade -y</code> or just install it using <code>sudo apt-get install cmake -y</code></p>
<h2 id="使用源码安装">使用源码安装</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="c1"># 更新软件包列表</span>
</span></span><span class="line"><span class="cl">sudo apt update
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 安装必要的依赖包</span>
</span></span><span class="line"><span class="cl">sudo apt install build-essential cmake python3-dev
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 下载 Clang/LLVM 11 的源代码</span>
</span></span><span class="line"><span class="cl">wget https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/llvm-11.0.0.src.tar.xz
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 解压源代码文件</span>
</span></span><span class="line"><span class="cl">tar xvf llvm-11.0.0.src.tar.xz
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 进入解压后的目录</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> llvm-11.0.0.src
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 创建一个新的目录，用于存放 Clang/LLVM 编译的结果</span>
</span></span><span class="line"><span class="cl">mkdir build
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> build
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 使用 cmake 编译 Clang/LLVM</span>
</span></span><span class="line"><span class="cl">cmake ..
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 编译 Clang/LLVM</span>
</span></span><span class="line"><span class="cl">make
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 安装 Clang/LLVM</span>
</span></span><span class="line"><span class="cl">sudo make install
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-chown 修改文件拥有者</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-chown%E4%BF%AE%E6%94%B9%E6%96%87%E4%BB%B6%E6%8B%A5%E6%9C%89%E8%80%85/</link>
      <pubDate>Sun, 04 Dec 2022 16:32:59 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-chown%E4%BF%AE%E6%94%B9%E6%96%87%E4%BB%B6%E6%8B%A5%E6%9C%89%E8%80%85/</guid>
      <description>&lt;p&gt;chown 命令用来变更文件或目录的拥有者或所属群组，通过 chown 改变文件的拥有者和群组。用户可以是用户名或者用户 ID；组可以是组名或者组 ID；文件是以空格分开的文件列表，文件名也支持通配符。&lt;/p&gt;
&lt;h2 id=&#34;命令格式&#34;&gt;命令格式&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chown &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;选项&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;用户或组&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;文件或目录&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-c或--changes           &lt;span class=&#34;c1&#34;&gt;#效果类似“-v”参数，但仅回报更改的部分；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-f或--quite或—-silent    &lt;span class=&#34;c1&#34;&gt;#不显示错误信息；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-h或--no-dereference    &lt;span class=&#34;c1&#34;&gt;#只对符号连接的文件作修改，而不更改其他任何相关文件；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-R或--recursive         &lt;span class=&#34;c1&#34;&gt;#递归处理，将指定目录下的所有文件及子目录一并处理；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-v或--version           &lt;span class=&#34;c1&#34;&gt;#显示指令执行过程；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--dereference          &lt;span class=&#34;c1&#34;&gt;#效果和“-h”参数相同；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--help                 &lt;span class=&#34;c1&#34;&gt;#在线帮助&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--reference&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&amp;lt;参考文件或目录&amp;gt;   &lt;span class=&#34;c1&#34;&gt;#把指定文件或目录的拥有者与所属群组全部设成和参考文件或目录的拥有者与所属群组相同；&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--version    &lt;span class=&#34;c1&#34;&gt;#显示版本信息。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;实例&#34;&gt;实例&lt;/h2&gt;
&lt;p&gt;将文件&lt;code&gt;test.md&lt;/code&gt;拥有者改为&lt;code&gt;nic&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chown nic test.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将目录&lt;code&gt;/home/nic/develop&lt;/code&gt;及其下面的所有文件、子目录的文件拥有者改为&lt;code&gt;nic&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chown -R nic /home/nic/develop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>chown 命令用来变更文件或目录的拥有者或所属群组，通过 chown 改变文件的拥有者和群组。用户可以是用户名或者用户 ID；组可以是组名或者组 ID；文件是以空格分开的文件列表，文件名也支持通配符。</p>
<h2 id="命令格式">命令格式</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">chown <span class="o">[</span>选项<span class="o">]</span> <span class="o">[</span>用户或组<span class="o">]</span> <span class="o">[</span>文件或目录<span class="o">]</span>
</span></span><span class="line"><span class="cl">-c或--changes           <span class="c1">#效果类似“-v”参数，但仅回报更改的部分；</span>
</span></span><span class="line"><span class="cl">-f或--quite或—-silent    <span class="c1">#不显示错误信息；</span>
</span></span><span class="line"><span class="cl">-h或--no-dereference    <span class="c1">#只对符号连接的文件作修改，而不更改其他任何相关文件；</span>
</span></span><span class="line"><span class="cl">-R或--recursive         <span class="c1">#递归处理，将指定目录下的所有文件及子目录一并处理；</span>
</span></span><span class="line"><span class="cl">-v或--version           <span class="c1">#显示指令执行过程；</span>
</span></span><span class="line"><span class="cl">--dereference          <span class="c1">#效果和“-h”参数相同；</span>
</span></span><span class="line"><span class="cl">--help                 <span class="c1">#在线帮助</span>
</span></span><span class="line"><span class="cl">--reference<span class="o">=</span>&lt;参考文件或目录&gt;   <span class="c1">#把指定文件或目录的拥有者与所属群组全部设成和参考文件或目录的拥有者与所属群组相同；</span>
</span></span><span class="line"><span class="cl">--version    <span class="c1">#显示版本信息。</span>
</span></span></code></pre></div><h2 id="实例">实例</h2>
<p>将文件<code>test.md</code>拥有者改为<code>nic</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">chown nic test.md
</span></span></code></pre></div><p>将目录<code>/home/nic/develop</code>及其下面的所有文件、子目录的文件拥有者改为<code>nic</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">chown -R nic /home/nic/develop
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-tree 显示目录结构</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-tree%E6%98%BE%E7%A4%BA%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84/</link>
      <pubDate>Sun, 04 Dec 2022 16:31:54 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-tree%E6%98%BE%E7%A4%BA%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84/</guid>
      <description>&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-a   &lt;span class=&#34;c1&#34;&gt;#显示所有文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-d   &lt;span class=&#34;c1&#34;&gt;#只显示目录（名称）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-l   &lt;span class=&#34;c1&#34;&gt;#显示链接文件的原始文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-f   &lt;span class=&#34;c1&#34;&gt;#显示所列出的文件或目录的完整目录路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-i   &lt;span class=&#34;c1&#34;&gt;#不以阶梯的形式显示文件或目录名称&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-q   &lt;span class=&#34;c1&#34;&gt;#将控制字符以?字符代替，显示文件和目录名称&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-N   &lt;span class=&#34;c1&#34;&gt;#直接显示文件或目录的名称&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-p   &lt;span class=&#34;c1&#34;&gt;#显示每个文件的权限信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-u   &lt;span class=&#34;c1&#34;&gt;#显示文件所有者或者uid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-g   &lt;span class=&#34;c1&#34;&gt;#显示文件所属组或者gid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-s   &lt;span class=&#34;c1&#34;&gt;#显示每个文件的大小信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-h   &lt;span class=&#34;c1&#34;&gt;#以可读的方式显示文件的大小信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-D   &lt;span class=&#34;c1&#34;&gt;#显示最后修改日期&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-v   &lt;span class=&#34;c1&#34;&gt;#按字母数字正序显示文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-r   &lt;span class=&#34;c1&#34;&gt;#按字母数字倒序显示文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-t   &lt;span class=&#34;c1&#34;&gt;#按最后时间排序显示文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-C   &lt;span class=&#34;c1&#34;&gt;#在文件和目录列表上加上色彩，便于区分文件类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-P pattern    &lt;span class=&#34;c1&#34;&gt;#只显示匹配正则表式的文件或目录名称&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-I pattern    &lt;span class=&#34;c1&#34;&gt;#与上结果相反&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;实例&#34;&gt;实例&lt;/h2&gt;
&lt;p&gt;显示当前目录及其子目录下的文件及目录名称&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ tree                 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── CODE_OF_CONDUCT.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── CONTRIBUTING.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Fedora-35
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── Dockerfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── Readme.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── LICENSE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Ubuntu-20
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── Dockerfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── Readme.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── init_edkrepo_conf.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── ubuntu20_dev_entrypoint.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── Windows-2022
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── Dockerfile
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    └── Readme.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; directories, &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt; files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;只显示一层目录结构&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ tree -L &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;              
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── CODE_OF_CONDUCT.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── CONTRIBUTING.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Fedora-35
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── LICENSE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Ubuntu-20
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── Windows-2022
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; directories, &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;只显示目录不显示文件&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ tree -d           
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Fedora-35
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Ubuntu-20
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── Windows-2022
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; directories
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">-a   <span class="c1">#显示所有文件</span>
</span></span><span class="line"><span class="cl">-d   <span class="c1">#只显示目录（名称）</span>
</span></span><span class="line"><span class="cl">-l   <span class="c1">#显示链接文件的原始文件</span>
</span></span><span class="line"><span class="cl">-f   <span class="c1">#显示所列出的文件或目录的完整目录路径</span>
</span></span><span class="line"><span class="cl">-i   <span class="c1">#不以阶梯的形式显示文件或目录名称</span>
</span></span><span class="line"><span class="cl">-q   <span class="c1">#将控制字符以?字符代替，显示文件和目录名称</span>
</span></span><span class="line"><span class="cl">-N   <span class="c1">#直接显示文件或目录的名称</span>
</span></span><span class="line"><span class="cl">-p   <span class="c1">#显示每个文件的权限信息</span>
</span></span><span class="line"><span class="cl">-u   <span class="c1">#显示文件所有者或者uid</span>
</span></span><span class="line"><span class="cl">-g   <span class="c1">#显示文件所属组或者gid</span>
</span></span><span class="line"><span class="cl">-s   <span class="c1">#显示每个文件的大小信息</span>
</span></span><span class="line"><span class="cl">-h   <span class="c1">#以可读的方式显示文件的大小信息</span>
</span></span><span class="line"><span class="cl">-D   <span class="c1">#显示最后修改日期</span>
</span></span><span class="line"><span class="cl">-v   <span class="c1">#按字母数字正序显示文件</span>
</span></span><span class="line"><span class="cl">-r   <span class="c1">#按字母数字倒序显示文件</span>
</span></span><span class="line"><span class="cl">-t   <span class="c1">#按最后时间排序显示文件</span>
</span></span><span class="line"><span class="cl">-C   <span class="c1">#在文件和目录列表上加上色彩，便于区分文件类型</span>
</span></span><span class="line"><span class="cl">-P pattern    <span class="c1">#只显示匹配正则表式的文件或目录名称</span>
</span></span><span class="line"><span class="cl">-I pattern    <span class="c1">#与上结果相反</span>
</span></span></code></pre></div><h2 id="实例">实例</h2>
<p>显示当前目录及其子目录下的文件及目录名称</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">$ tree                 
</span></span><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">├── CODE_OF_CONDUCT.md
</span></span><span class="line"><span class="cl">├── CONTRIBUTING.md
</span></span><span class="line"><span class="cl">├── Fedora-35
</span></span><span class="line"><span class="cl">│   ├── Dockerfile
</span></span><span class="line"><span class="cl">│   └── Readme.md
</span></span><span class="line"><span class="cl">├── LICENSE
</span></span><span class="line"><span class="cl">├── README.md
</span></span><span class="line"><span class="cl">├── Ubuntu-20
</span></span><span class="line"><span class="cl">│   ├── Dockerfile
</span></span><span class="line"><span class="cl">│   ├── Readme.md
</span></span><span class="line"><span class="cl">│   ├── init_edkrepo_conf.sh
</span></span><span class="line"><span class="cl">│   └── ubuntu20_dev_entrypoint.sh
</span></span><span class="line"><span class="cl">└── Windows-2022
</span></span><span class="line"><span class="cl">    ├── Dockerfile
</span></span><span class="line"><span class="cl">    └── Readme.md
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="m">3</span> directories, <span class="m">12</span> files
</span></span></code></pre></div><p>只显示一层目录结构</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">$ tree -L <span class="m">1</span>              
</span></span><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">├── CODE_OF_CONDUCT.md
</span></span><span class="line"><span class="cl">├── CONTRIBUTING.md
</span></span><span class="line"><span class="cl">├── Fedora-35
</span></span><span class="line"><span class="cl">├── LICENSE
</span></span><span class="line"><span class="cl">├── README.md
</span></span><span class="line"><span class="cl">├── Ubuntu-20
</span></span><span class="line"><span class="cl">└── Windows-2022
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="m">3</span> directories, <span class="m">4</span> files
</span></span></code></pre></div><p>只显示目录不显示文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">$ tree -d           
</span></span><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">├── Fedora-35
</span></span><span class="line"><span class="cl">├── Ubuntu-20
</span></span><span class="line"><span class="cl">└── Windows-2022
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="m">3</span> directories
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>更换 Debian 软件更新源</title>
      <link>https://lifeislife.cn/posts/linux%E6%9B%B4%E6%8D%A2debian%E8%BD%AF%E4%BB%B6%E6%9B%B4%E6%96%B0%E6%BA%90/</link>
      <pubDate>Sat, 05 Nov 2022 09:27:52 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%9B%B4%E6%8D%A2debian%E8%BD%AF%E4%BB%B6%E6%9B%B4%E6%96%B0%E6%BA%90/</guid>
      <description>&lt;h2 id=&#34;确认-debian-版本&#34;&gt;确认 Debian 版本&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat /etc/os-release               
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PRETTY_NAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Debian GNU/Linux 10 (buster)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;NAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Debian GNU/Linux&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;VERSION_ID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;VERSION&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;10 (buster)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;VERSION_CODENAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;buster
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;ID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;debian
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;HOME_URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.debian.org/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SUPPORT_URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;https://www.debian.org/support&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;BUG_REPORT_URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;https://bugs.debian.org/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;括号里的&lt;code&gt;buster&lt;/code&gt;就是版本信息。&lt;/p&gt;
&lt;h2 id=&#34;获取镜像地址&#34;&gt;获取镜像地址&lt;/h2&gt;
&lt;p&gt;打开&lt;a href=&#34;https://mirrors.tuna.tsinghua.edu.cn/help/debian/&#34;&gt;debian | 清华大学开源软件镜像站&lt;/a&gt;，选择&lt;code&gt;buster&lt;/code&gt;版本，复制所有镜像地址。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/11/05/54a39f7d33cf13259607144e03747e5a.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/11/05/54a39f7d33cf13259607144e03747e5a.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 默认注释了源码镜像以提高 apt update 速度，如有需要可自行取消注释&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;备份原文件&#34;&gt;备份原文件&lt;/h2&gt;
&lt;p&gt;这也算是系统文件的一部分，还是保险一点，出错了再改回来。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;打开并修改&#34;&gt;打开并修改&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo vim /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;vim&lt;/code&gt;用的不习惯的估计会和我一样找全选内容怎么操作。教给你了
在命令模式下，就是按一下&lt;code&gt;esc&lt;/code&gt;键，然后输入&lt;code&gt;ggvG&lt;/code&gt;。具体什么含义看&lt;code&gt;VIM 笔记&lt;/code&gt;吧，选择后直接&lt;code&gt;delete&lt;/code&gt;删除，镜像地址粘贴进去。保存退出。&lt;/p&gt;
&lt;h2 id=&#34;更新&#34;&gt;更新&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get dist-upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="确认-debian-版本">确认 Debian 版本</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ cat /etc/os-release               
</span></span><span class="line"><span class="cl"><span class="nv">PRETTY_NAME</span><span class="o">=</span><span class="s2">&#34;Debian GNU/Linux 10 (buster)&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">NAME</span><span class="o">=</span><span class="s2">&#34;Debian GNU/Linux&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">VERSION_ID</span><span class="o">=</span><span class="s2">&#34;10&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">VERSION</span><span class="o">=</span><span class="s2">&#34;10 (buster)&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">VERSION_CODENAME</span><span class="o">=</span>buster
</span></span><span class="line"><span class="cl"><span class="nv">ID</span><span class="o">=</span>debian
</span></span><span class="line"><span class="cl"><span class="nv">HOME_URL</span><span class="o">=</span><span class="s2">&#34;https://www.debian.org/&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">SUPPORT_URL</span><span class="o">=</span><span class="s2">&#34;https://www.debian.org/support&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">BUG_REPORT_URL</span><span class="o">=</span><span class="s2">&#34;https://bugs.debian.org/&#34;</span>
</span></span></code></pre></div><p>括号里的<code>buster</code>就是版本信息。</p>
<h2 id="获取镜像地址">获取镜像地址</h2>
<p>打开<a href="https://mirrors.tuna.tsinghua.edu.cn/help/debian/">debian | 清华大学开源软件镜像站</a>，选择<code>buster</code>版本，复制所有镜像地址。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/11/05/54a39f7d33cf13259607144e03747e5a.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/11/05/54a39f7d33cf13259607144e03747e5a.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 默认注释了源码镜像以提高 apt update 速度，如有需要可自行取消注释</span>
</span></span><span class="line"><span class="cl">deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free
</span></span><span class="line"><span class="cl"><span class="c1"># deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free</span>
</span></span><span class="line"><span class="cl">deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free
</span></span><span class="line"><span class="cl"><span class="c1"># deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-updates main contrib non-free</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">deb https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free
</span></span><span class="line"><span class="cl"><span class="c1"># deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ buster-backports main contrib non-free</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">deb https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free
</span></span><span class="line"><span class="cl"><span class="c1"># deb-src https://mirrors.tuna.tsinghua.edu.cn/debian-security buster/updates main contrib non-free</span>
</span></span></code></pre></div><h2 id="备份原文件">备份原文件</h2>
<p>这也算是系统文件的一部分，还是保险一点，出错了再改回来。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
</span></span></code></pre></div><h2 id="打开并修改">打开并修改</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo vim /etc/apt/sources.list
</span></span></code></pre></div><p><code>vim</code>用的不习惯的估计会和我一样找全选内容怎么操作。教给你了
在命令模式下，就是按一下<code>esc</code>键，然后输入<code>ggvG</code>。具体什么含义看<code>VIM 笔记</code>吧，选择后直接<code>delete</code>删除，镜像地址粘贴进去。保存退出。</p>
<h2 id="更新">更新</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get dist-upgrade
</span></span><span class="line"><span class="cl">sudo apt-get upgrade
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Makefile 基础</title>
      <link>https://lifeislife.cn/posts/makefile%E5%9F%BA%E7%A1%80/</link>
      <pubDate>Mon, 26 Sep 2022 21:36:18 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/makefile%E5%9F%BA%E7%A1%80/</guid>
      <description>&lt;h2 id=&#34;目标依赖命令&#34;&gt;目标、依赖、命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;目标就是我们要去 make xxx 的那个 xxx，就是我们最终要生成的东西。&lt;/li&gt;
&lt;li&gt;依赖是用来生成目录的原材料&lt;/li&gt;
&lt;li&gt;命令就是加工方法，所以 make xxx 的过程其实就是使用命令将依赖加工成目标的过程。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;通配符--和-makefile-自动推导&#34;&gt;通配符 &lt;code&gt;%&lt;/code&gt; 和 Makefile 自动推导&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%&lt;/code&gt; 是 Makefile 中的通配符，代表一个或几个字母。也就是说&lt;code&gt;%.o&lt;/code&gt;就代表所有以&lt;code&gt;.o&lt;/code&gt;为结尾的文件。&lt;/li&gt;
&lt;li&gt;所谓自动推导其实就是 Makefile 的规则。当 Makefile 需要某一个目标时，他会把这个目标去套规则说明，一旦套上了某个规则说明，则 Makefile 会试图寻找这个规则中的依赖，如果能找到则会执行这个规则用依赖生成目标。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;makefile-中定义和使用变量&#34;&gt;Makefile 中定义和使用变量&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Makefile 中定义和使用变量，和 shell 脚本中非常相似。相似的是都没有变量类型，直接定义使用，引用变量时用&lt;code&gt;$var&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;伪目标phony&#34;&gt;伪目标（&lt;code&gt;.PHONY&lt;/code&gt;）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;伪目标意思是这个目标本身不代表一个文件，执行这个目标不是为了得到某个文件或东西，而是单纯为了执行这个目标下面的命令。&lt;/li&gt;
&lt;li&gt;伪目标一般都没有依赖，因为执行伪目标就是为了执行目标下面的命令。既然一定要执行命令了那就不必加依赖，因为不加依赖意思就是无条件执行。&lt;/li&gt;
&lt;li&gt;伪目标可以直接写，不影响使用；但是有时候为了明确声明这个目标是伪目标会在伪目标的前面用&lt;code&gt;.PHONY&lt;/code&gt;来明确声明它是伪目标。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;makfile-中引用其他-makefile&#34;&gt;Makfile 中引用其他 Makefile&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;有时候 Makefile 总体比较复杂，因此分成好几个 Makefile 来写。然后在主 Makefile 中引用其他的，用 &lt;code&gt;include&lt;/code&gt; 指令来引用。引用的效果也是原地展开，和 C 语言中的头文件包含非常相似。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;赋值&#34;&gt;赋值&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;=&lt;/code&gt;最简单的赋值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:=&lt;/code&gt;一般也是赋值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上这两个大部分情况下效果是一样的，但是有时候不一样。用&lt;code&gt;=&lt;/code&gt;赋值的变量，在被解析时他的值取决于最后一次赋值时的值，所以你看变量引用的值时不能只往前面看，还要往后面看。用&lt;code&gt;:=&lt;/code&gt;来赋值的，则是就地直接解析，只用往前看即可。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;?=&lt;/code&gt;如果变量前面并没有赋值过则执行这条赋值，如果前面已经赋值过了则本行被忽略。（实验可以看出：所谓的没有赋值过其实就是这个变量没有被定义过）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+=&lt;/code&gt;用来给一个已经赋值的变量接续赋值，意思就是把这次的值加到原来的值的后面，有点类似于 &lt;code&gt;strcat&lt;/code&gt;。（注意一个细节，&lt;code&gt;+=&lt;/code&gt;续接的内容和原来的内容之间会自动加一个空格隔开）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意：Makefile 中并不要求赋值运算符两边一定要有空格或者无空格，这一点比 shell 的格式要求要松一些。&lt;/p&gt;
&lt;h2 id=&#34;makefile-的环境变量&#34;&gt;Makefile 的环境变量&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;makefile 中用 &lt;code&gt;export&lt;/code&gt; 导出的就是环境变量。一般情况下要求环境变量名用大写，普通变量名用小写。&lt;/li&gt;
&lt;li&gt;环境变量和普通变量不同，可以这样理解：环境变量类似于整个工程中所有 Makefile 之间可以共享的全局变量，而普通变量只是当前本 Makefile 中使用的局部变量。所以要注意：定义了一个环境变量会影响到工程中别的 Makefile 文件，因此要小心。&lt;/li&gt;
&lt;li&gt;Makefile 中可能有一些环境变量可能是 makefile 本身自己定义的内部的环境变量或者是当前的执行环境提供的环境变量（譬如我们在 &lt;code&gt;make&lt;/code&gt; 执行时给 makefile 传参。&lt;code&gt;make CC=arm-linux-gcc&lt;/code&gt;，其实就是给当前 Makefile 传了一个环境变量 &lt;code&gt;CC&lt;/code&gt;，值是 &lt;code&gt;arm-linux-gcc&lt;/code&gt;。我们在 &lt;code&gt;make&lt;/code&gt; 时给 &lt;code&gt;makefile&lt;/code&gt; 传的环境变量值优先级最高的，可以覆盖 makefile 中的赋值）。这就好像 C 语言中编译器预定义的宏&lt;code&gt;__LINE__&lt;/code&gt; &lt;code&gt;__FUNCTION__&lt;/code&gt;等一样。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;makefile-中使用通配符&#34;&gt;Makefile 中使用通配符&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt;：若干个任意字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt;：1 个任意字符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[]&lt;/code&gt;：将 &lt;code&gt;[]&lt;/code&gt; 中的字符依次去和外面的结合匹配&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还有个&lt;code&gt;%&lt;/code&gt;，也是通配符，表示任意多个字符，和&lt;code&gt;*&lt;/code&gt;很相似，但是&lt;code&gt;%&lt;/code&gt;一般只用于规则描述中，又叫做规则通配符。&lt;/p&gt;
&lt;h2 id=&#34;makefile-的自动变量&#34;&gt;Makefile 的自动变量&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;为什么使用自动变量。在有些情况下文件集合中文件非常多，描述的时候很麻烦，所以我们 Makefile 就用一些特殊的符号来替代符合某种条件的文件集，这就形成了自动变量。&lt;/li&gt;
&lt;li&gt;自动变量的含义：预定义的特殊意义的符号。就类似于 C 语言编译器中预制的那些宏&lt;code&gt;__FILE__&lt;/code&gt;一样。&lt;/li&gt;
&lt;li&gt;常见自动变量：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$@&lt;/code&gt;：规则的目标文件名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&amp;lt;&lt;/code&gt;：规则的依赖文件名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$^&lt;/code&gt;：依赖的文件集合&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;其他&#34;&gt;其他&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Makefile 中的注释用&lt;code&gt;#&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;在 makefile 的命令行中前面的&lt;code&gt;@&lt;/code&gt;表示静默执行&lt;/li&gt;
&lt;li&gt;Makefile 中默认情况下在执行一行命令前会先把这行命令给打印出来，然后再执行这行命令&lt;/li&gt;
&lt;li&gt;如果你不想看到命令本身，只想看到命令执行就静默执行即可&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<h2 id="目标依赖命令">目标、依赖、命令</h2>
<ul>
<li>目标就是我们要去 make xxx 的那个 xxx，就是我们最终要生成的东西。</li>
<li>依赖是用来生成目录的原材料</li>
<li>命令就是加工方法，所以 make xxx 的过程其实就是使用命令将依赖加工成目标的过程。</li>
</ul>
<h2 id="通配符--和-makefile-自动推导">通配符 <code>%</code> 和 Makefile 自动推导</h2>
<ul>
<li><code>%</code> 是 Makefile 中的通配符，代表一个或几个字母。也就是说<code>%.o</code>就代表所有以<code>.o</code>为结尾的文件。</li>
<li>所谓自动推导其实就是 Makefile 的规则。当 Makefile 需要某一个目标时，他会把这个目标去套规则说明，一旦套上了某个规则说明，则 Makefile 会试图寻找这个规则中的依赖，如果能找到则会执行这个规则用依赖生成目标。</li>
</ul>
<h2 id="makefile-中定义和使用变量">Makefile 中定义和使用变量</h2>
<ul>
<li>Makefile 中定义和使用变量，和 shell 脚本中非常相似。相似的是都没有变量类型，直接定义使用，引用变量时用<code>$var</code>。</li>
</ul>
<h2 id="伪目标phony">伪目标（<code>.PHONY</code>）</h2>
<ul>
<li>伪目标意思是这个目标本身不代表一个文件，执行这个目标不是为了得到某个文件或东西，而是单纯为了执行这个目标下面的命令。</li>
<li>伪目标一般都没有依赖，因为执行伪目标就是为了执行目标下面的命令。既然一定要执行命令了那就不必加依赖，因为不加依赖意思就是无条件执行。</li>
<li>伪目标可以直接写，不影响使用；但是有时候为了明确声明这个目标是伪目标会在伪目标的前面用<code>.PHONY</code>来明确声明它是伪目标。</li>
</ul>
<h2 id="makfile-中引用其他-makefile">Makfile 中引用其他 Makefile</h2>
<ul>
<li>有时候 Makefile 总体比较复杂，因此分成好几个 Makefile 来写。然后在主 Makefile 中引用其他的，用 <code>include</code> 指令来引用。引用的效果也是原地展开，和 C 语言中的头文件包含非常相似。</li>
</ul>
<h2 id="赋值">赋值</h2>
<ul>
<li><code>=</code>最简单的赋值</li>
<li><code>:=</code>一般也是赋值</li>
</ul>
<p>以上这两个大部分情况下效果是一样的，但是有时候不一样。用<code>=</code>赋值的变量，在被解析时他的值取决于最后一次赋值时的值，所以你看变量引用的值时不能只往前面看，还要往后面看。用<code>:=</code>来赋值的，则是就地直接解析，只用往前看即可。</p>
<ul>
<li><code>?=</code>如果变量前面并没有赋值过则执行这条赋值，如果前面已经赋值过了则本行被忽略。（实验可以看出：所谓的没有赋值过其实就是这个变量没有被定义过）</li>
<li><code>+=</code>用来给一个已经赋值的变量接续赋值，意思就是把这次的值加到原来的值的后面，有点类似于 <code>strcat</code>。（注意一个细节，<code>+=</code>续接的内容和原来的内容之间会自动加一个空格隔开）</li>
</ul>
<p>注意：Makefile 中并不要求赋值运算符两边一定要有空格或者无空格，这一点比 shell 的格式要求要松一些。</p>
<h2 id="makefile-的环境变量">Makefile 的环境变量</h2>
<ul>
<li>makefile 中用 <code>export</code> 导出的就是环境变量。一般情况下要求环境变量名用大写，普通变量名用小写。</li>
<li>环境变量和普通变量不同，可以这样理解：环境变量类似于整个工程中所有 Makefile 之间可以共享的全局变量，而普通变量只是当前本 Makefile 中使用的局部变量。所以要注意：定义了一个环境变量会影响到工程中别的 Makefile 文件，因此要小心。</li>
<li>Makefile 中可能有一些环境变量可能是 makefile 本身自己定义的内部的环境变量或者是当前的执行环境提供的环境变量（譬如我们在 <code>make</code> 执行时给 makefile 传参。<code>make CC=arm-linux-gcc</code>，其实就是给当前 Makefile 传了一个环境变量 <code>CC</code>，值是 <code>arm-linux-gcc</code>。我们在 <code>make</code> 时给 <code>makefile</code> 传的环境变量值优先级最高的，可以覆盖 makefile 中的赋值）。这就好像 C 语言中编译器预定义的宏<code>__LINE__</code> <code>__FUNCTION__</code>等一样。</li>
</ul>
<h2 id="makefile-中使用通配符">Makefile 中使用通配符</h2>
<ul>
<li><code>*</code>：若干个任意字符</li>
<li><code>?</code>：1 个任意字符</li>
<li><code>[]</code>：将 <code>[]</code> 中的字符依次去和外面的结合匹配</li>
</ul>
<p>还有个<code>%</code>，也是通配符，表示任意多个字符，和<code>*</code>很相似，但是<code>%</code>一般只用于规则描述中，又叫做规则通配符。</p>
<h2 id="makefile-的自动变量">Makefile 的自动变量</h2>
<ul>
<li>为什么使用自动变量。在有些情况下文件集合中文件非常多，描述的时候很麻烦，所以我们 Makefile 就用一些特殊的符号来替代符合某种条件的文件集，这就形成了自动变量。</li>
<li>自动变量的含义：预定义的特殊意义的符号。就类似于 C 语言编译器中预制的那些宏<code>__FILE__</code>一样。</li>
<li>常见自动变量：
<ul>
<li><code>$@</code>：规则的目标文件名</li>
<li><code>$&lt;</code>：规则的依赖文件名</li>
<li><code>$^</code>：依赖的文件集合</li>
</ul>
</li>
</ul>
<h2 id="其他">其他</h2>
<ul>
<li>Makefile 中的注释用<code>#</code></li>
<li>在 makefile 的命令行中前面的<code>@</code>表示静默执行</li>
<li>Makefile 中默认情况下在执行一行命令前会先把这行命令给打印出来，然后再执行这行命令</li>
<li>如果你不想看到命令本身，只想看到命令执行就静默执行即可</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>嵌入式 Shell 基础</title>
      <link>https://lifeislife.cn/posts/%E5%B5%8C%E5%85%A5%E5%BC%8Fshell%E5%9F%BA%E7%A1%80/</link>
      <pubDate>Sun, 25 Sep 2022 22:35:16 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E5%B5%8C%E5%85%A5%E5%BC%8Fshell%E5%9F%BA%E7%A1%80/</guid>
      <description>&lt;h2 id=&#34;脚本语言&#34;&gt;脚本语言&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;常用的脚本语言有 sh、bash、csh、ksh、perl、python；&lt;/li&gt;
&lt;li&gt;在 Linux 下常用的脚本语言其实就是 bash、sh；&lt;/li&gt;
&lt;li&gt;脚本语言一般在嵌入式中应用，主要是用来做配置。（一个复杂的嵌入式程序都是可配置的，配置过程就是用脚本语言来实现的）自然不会使用过于复杂的脚本语言特性，因此只需要针对性的学习即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;shell-脚本的运行机制&#34;&gt;shell 脚本的运行机制&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;C/C++ 语言这种编写过程是：编写出源代码（源代码是不能直接运行的）然后编译链接形成可执行二进制程序，然后才能运行；而脚本程序不同，脚本程序编写好后源代码即可直接运行（没有编译链接过程）；&lt;/li&gt;
&lt;li&gt;shell 程序是解释运行的，所谓解释运行就是说当我们执行一个 shell 程序时，shell 解析器会逐行的解释 shell 程序代码，然后一行一行的去运行。（顺序结构）&lt;/li&gt;
&lt;li&gt;CPU 实际只认识二进制代码，根本不认识源代码。脚本程序源代码其实也不是二进制代码，CPU 也不认识，也不能直接执行。只不过脚本程序的编译链接过程不是以脚本程序源代码为单位进行的，而是在脚本运行过程中逐行的解释执行时才去完成脚本程序源代码转成二进制的过程（不一定是编译链接，因为这行脚本程序可能早就编译连接好了，这里我们只是调用它）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;动手写第一个-shell&#34;&gt;动手写第一个 shell&lt;/h2&gt;
&lt;h3 id=&#34;编辑器与编译器&#34;&gt;编辑器与编译器&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;shell 程序是文本格式的，只要是文本编辑器都可以。但是因为我们的 shell 是要在 Linux 系统下运行的，所以换行符必须是&lt;code&gt;\n&lt;/code&gt;，而 Windows 下的换行符是&lt;code&gt;\r\n&lt;/code&gt;，因此 Windows 中的编辑器写的 shell 不能在 Linux 下运行。&lt;/li&gt;
&lt;li&gt;编译器不涉及，因为 shell 是解释性语言，直接编辑完就可以运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;shell-程序运行的运行的三种方法&#34;&gt;shell 程序运行的运行的三种方法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;./xx.sh&lt;/code&gt;，和运行二进制可执行程序方法一样。这样运行 shell 要求 shell 程序必须具有可执行权限。&lt;code&gt;chmod a+x xx.sh&lt;/code&gt; 来添加可执行权限。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;source xx.sh&lt;/code&gt;，&lt;code&gt;source&lt;/code&gt; 是 Linux 的一个命令，这个命令就是用来执行脚本程序的。这样运行不需要脚本具有可执行权限。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bash xx.sh&lt;/code&gt;，&lt;code&gt;bash&lt;/code&gt; 是一个脚本程序解释器，本质上是一个可执行程序。这样执行相当于我们执行了 &lt;code&gt;bash&lt;/code&gt; 程序，然后把 &lt;code&gt;xx.sh&lt;/code&gt; 作为 &lt;code&gt;argv[1]&lt;/code&gt; 传给他运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;hello-world-程序和解释&#34;&gt;hello world 程序和解释&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;shell 程序的第一行一般都是以&lt;code&gt;#!/bin/sh&lt;/code&gt;开始，这行话的意思就是指定 shell 程序执行时被哪个解释器解释执行。所以我们这里写上&lt;code&gt;/bin/sh&lt;/code&gt;意思就是这个&lt;code&gt;shell&lt;/code&gt;将来被当前机器中&lt;code&gt;/bin&lt;/code&gt;目录下的&lt;code&gt;sh&lt;/code&gt;可执行程序执行。可以将第一行写为&lt;code&gt;#!/bin/bash&lt;/code&gt;来指定使用&lt;code&gt;bash&lt;/code&gt;执行该脚本。&lt;/li&gt;
&lt;li&gt;脚本中的注释使用&lt;code&gt;#&lt;/code&gt;，&lt;code&gt;#&lt;/code&gt;开头的行是注释行。如果有多行需要注释，每行前面都要加&lt;code&gt;#&lt;/code&gt;。（&lt;code&gt;#&lt;/code&gt;就相当于是 C 语言中的&lt;code&gt;//&lt;/code&gt;）;&lt;/li&gt;
&lt;li&gt;shell 程序的正文，由很多行 shell 语句构成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;shell-语法&#34;&gt;shell 语法&lt;/h2&gt;
&lt;p&gt;shell 就是把以前命令行中键入执行的命令写成了程序。shell 其实就是为了避免反复的在命令行下手工输入而发明的一种把手工输入步骤记录下来，然后通过执行 shell 脚本程序就能再次复述原来记录的手工输入过程的一种技术。&lt;/p&gt;
&lt;h3 id=&#34;shell-中的变量定义和引用&#34;&gt;shell 中的变量定义和引用&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;变量定义和初始化。shell 是弱类型语言（语言中的变量如果有明确的类型则属于强类型语言；变量没有明确类型就是弱类型语言），和 C 语言不同。在 shell 编程中定义变量不需要制定类型，也没有类型这个概念。&lt;/li&gt;
&lt;li&gt;变量定义时可以初始化，使用&lt;code&gt;=&lt;/code&gt;进行初始化赋值。在 shell 中赋值的=两边是不能有空格的。
注意：shell 对语法非常在意，非常严格。很多地方空格都是必须没有或者必须有，而且不能随意有没有空格。&lt;/li&gt;
&lt;li&gt;变量赋值，变量定义后可以再次赋值，新的赋值会覆盖老的赋值。shell 中并不刻意区分变量的定义和赋值，反正每个变量就是一个符号，这个符号的值就是最后一个给他赋值时的值。&lt;/li&gt;
&lt;li&gt;变量引用。shell 中引用一个变量必须使用&lt;code&gt;$&lt;/code&gt;符号，&lt;code&gt;$&lt;/code&gt;符号就是变量解引用符号。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意：&lt;code&gt;$&lt;/code&gt;符号后面跟一个字符串，这个字符串就会被当作变量去解析。如果这个字符串本身没有定义，执行时并不会报错，而是把这个变量解析为空。也就是说在 shell 中没有被定义的变量其实就相当于是一个定义并赋值为空的变量。&lt;/p&gt;
&lt;p&gt;注意：变量引用的时候可以&lt;code&gt;$var&lt;/code&gt;，也可以&lt;code&gt;${var}&lt;/code&gt;。这两种的区别是在某些情况下只能用&lt;code&gt;${var}&lt;/code&gt;而不能简单的&lt;code&gt;$var&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;shell-中无引用单引号和双引号的区别&#34;&gt;shell 中无引用、单引号和双引号的区别&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;shell 中使用字符串可以不加双引号，直接使用。而且有空格时也可以，但是缺陷是不能输出&lt;code&gt;&amp;quot;&lt;/code&gt;或者其他转义字符。&lt;/li&gt;
&lt;li&gt;shell 中也可以使用单引号来表示字符串，也是直接使用的，不能输出转义字符。&lt;/li&gt;
&lt;li&gt;单引号中：完全字面替换（不可包含单引号本身）&lt;/li&gt;
&lt;li&gt;双引号中：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt;加变量名可以取变量的值&lt;/li&gt;
&lt;li&gt;反引号仍表示命令替换&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\$&lt;/code&gt;表示&lt;code&gt;$&lt;/code&gt;的字面值（输出$符号）&lt;/li&gt;
&lt;li&gt;`表示`的字面值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\&amp;quot;&lt;/code&gt;表示&lt;code&gt;&amp;quot;&lt;/code&gt;的字面值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\\&lt;/code&gt;表示&lt;code&gt;\&lt;/code&gt;的字面值&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除以上情况之外，在其它字符前面的\无特殊含义，只表示字面值。&lt;/p&gt;
&lt;p&gt;单引号会原样输出，双引号可以调用命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PATH_A&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;`pwd`/include&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PATH_B&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;`pwd`/include&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$PATH_A&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /home/a/b/include&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$PATH_B&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# `pwd`/include&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;shell-中调用-linux-命令&#34;&gt;shell 中调用 Linux 命令&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;直接执行&lt;/li&gt;
&lt;li&gt;反引号括起来执行。有时候我们在 shell 中调用 Linux 命令是为了得到这个命令的返回值（结果值），这时候就适合用一对反引号 (键盘上 ESC 按键下面的那个按键，和&lt;code&gt;~&lt;/code&gt;在一个按键上) 来调用执行命令。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;shell-中的选择分支结构&#34;&gt;shell 中的选择分支结构&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;shell 的 &lt;code&gt;if&lt;/code&gt; 语言用法很多，在此只介绍常用的，其他感兴趣可以自己去学&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;典型&lt;code&gt;if&lt;/code&gt;语言格式：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; 表达式 &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  xxx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  yyy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  zzz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  xxx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ddd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  uuu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;if-的典型应用&#34;&gt;if 的典型应用&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-f&lt;/code&gt;判断文件是否存在，注意&lt;code&gt;[]&lt;/code&gt;里面&lt;strong&gt;前后都有空格&lt;/strong&gt;，不能省略&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-d&lt;/code&gt;判断目录是否存在&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;&amp;quot;str1&amp;quot; = &amp;quot;str2&amp;quot;&lt;/code&gt;判断字符串是否相等，注意&lt;strong&gt;用一个等号而不是两个&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;判断数字是否相等&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-eq&lt;/code&gt;等于&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-gt&lt;/code&gt;大于&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-lt&lt;/code&gt;小于&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-ge&lt;/code&gt;大于等于&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-le&lt;/code&gt;小于等于&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-z&lt;/code&gt;判断字符串是否为空，注意&lt;code&gt;-z&lt;/code&gt;判断时如果变量本身没定义也是不成立（也就是说-z 认为没定义不等于为空）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-o&lt;/code&gt;表示逻辑或，连接两个表达式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;if [ 10 -eq 10 -o  ]; then&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; &lt;code&gt;||&lt;/code&gt;表示逻辑与和逻辑或&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;shell-中的循环结构&#34;&gt;shell 中的循环结构&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;for&lt;/code&gt; 循环，要求能看懂、能改即可。不要求能够完全不参考写出来。因为毕竟嵌入式并不需要完全重新手写。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;while&lt;/code&gt; 循环，和 C 语言的循环在逻辑上无差别，要注意很多格式要求，譬如：&lt;code&gt;while&lt;/code&gt; 后面的 &lt;code&gt;[]&lt;/code&gt; 两边都有空格，&lt;code&gt;[]&lt;/code&gt; 后面有分号（如果 do 放在一行的话），&lt;code&gt;i++&lt;/code&gt;的写法中有两层括号。&lt;/p&gt;
&lt;h3 id=&#34;echo-的创建和追加输入文件&#34;&gt;echo 的创建和追加输入文件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在 shell 中可以直接使用 &lt;code&gt;echo&lt;/code&gt; 指令新建一个文件，并且将一些内容传入这个文件中。创建文件并输入内容的关键就是&lt;code&gt;&amp;gt;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;还可以使用 &lt;code&gt;echo&lt;/code&gt; 指令配合追加符号&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; 向一个已经存在的文件末尾追加输入内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;shell-中其他值得关注的知识点&#34;&gt;shell 中其他值得关注的知识点&lt;/h3&gt;
&lt;h4 id=&#34;case-语句&#34;&gt;case 语句&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;shell 中的 case 语句和 C 语言中的 switch case 语句作用一样，格式有差异&lt;/li&gt;
&lt;li&gt;shell 中的 case 语句天生没有 &lt;code&gt;break&lt;/code&gt;，也不需要&lt;code&gt;break&lt;/code&gt;，和 C 语言中的 switch case 不同。shell 中的 case 默认就是匹配上哪个执行哪个，不会说执行完了还去执行后面的其他 case&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;调用-shell-程序的传参&#34;&gt;调用 shell 程序的传参&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;C 语言中可以通过 &lt;code&gt;main&lt;/code&gt; 函数的 &lt;code&gt;argc&lt;/code&gt; 和 &lt;code&gt;argv&lt;/code&gt; 给程序传参&lt;/li&gt;
&lt;li&gt;shell 程序本身也可以在调用时传参给他。在 shell 程序内部使用传参也是使用的一些特定符号来表示的，包括：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$#&lt;/code&gt;表示调用该 shell 时传参的个数。（&lt;code&gt;$#&lt;/code&gt;计数时只考虑真正的参数个数）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$0、$1、$2·····&lt;/code&gt;则依次表示传参的各个参数&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./a.out aa bb cc     
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# argc = 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# argv[0] = ./a.out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# argv[1] 是第一个有效参数····&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; a.sh aa bb cc  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# $# = 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# $0是执行这个 shell 程序的解析程序的名字&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# $1是第一个有效参数的值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# $2是第 2 个有效参数的值·····&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;while-循环和-case-语言和传参结合&#34;&gt;while 循环和 case 语言和传参结合&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;shell 中的 &lt;code&gt;break&lt;/code&gt; 关键字和 &lt;code&gt;C&lt;/code&gt; 语言中意义相同（都是跳出）但是用法不同。因为 shell 中 &lt;code&gt;case&lt;/code&gt; 语句默认不用 &lt;code&gt;break&lt;/code&gt; 的，因此在 &lt;code&gt;shell&lt;/code&gt; 中 &lt;code&gt;break&lt;/code&gt; 只用于循环跳出。所以当 &lt;code&gt;while&lt;/code&gt; 中内嵌 &lt;code&gt;case&lt;/code&gt; 语句时，&lt;code&gt;case&lt;/code&gt; 中的 &lt;code&gt;break&lt;/code&gt; 是跳出外层的 &lt;code&gt;while&lt;/code&gt; 循环的，不是用来跳出 &lt;code&gt;case&lt;/code&gt; 语句的。&lt;/li&gt;
&lt;li&gt;shell 中的&lt;code&gt;$# $1&lt;/code&gt;等内置变量的值是可以被改变，被 &lt;code&gt;shift&lt;/code&gt; 指令改变。&lt;code&gt;shift&lt;/code&gt; 指令有点像左移运算符，把我们给 shell 程序的传参左移了一个移出去了，原来的&lt;code&gt;$2&lt;/code&gt;变成了新的&lt;code&gt;$1&lt;/code&gt;，原来的&lt;code&gt;$#&lt;/code&gt;少了 1 个。&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<h2 id="脚本语言">脚本语言</h2>
<ul>
<li>常用的脚本语言有 sh、bash、csh、ksh、perl、python；</li>
<li>在 Linux 下常用的脚本语言其实就是 bash、sh；</li>
<li>脚本语言一般在嵌入式中应用，主要是用来做配置。（一个复杂的嵌入式程序都是可配置的，配置过程就是用脚本语言来实现的）自然不会使用过于复杂的脚本语言特性，因此只需要针对性的学习即可。</li>
</ul>
<h2 id="shell-脚本的运行机制">shell 脚本的运行机制</h2>
<ul>
<li>C/C++ 语言这种编写过程是：编写出源代码（源代码是不能直接运行的）然后编译链接形成可执行二进制程序，然后才能运行；而脚本程序不同，脚本程序编写好后源代码即可直接运行（没有编译链接过程）；</li>
<li>shell 程序是解释运行的，所谓解释运行就是说当我们执行一个 shell 程序时，shell 解析器会逐行的解释 shell 程序代码，然后一行一行的去运行。（顺序结构）</li>
<li>CPU 实际只认识二进制代码，根本不认识源代码。脚本程序源代码其实也不是二进制代码，CPU 也不认识，也不能直接执行。只不过脚本程序的编译链接过程不是以脚本程序源代码为单位进行的，而是在脚本运行过程中逐行的解释执行时才去完成脚本程序源代码转成二进制的过程（不一定是编译链接，因为这行脚本程序可能早就编译连接好了，这里我们只是调用它）。</li>
</ul>
<h2 id="动手写第一个-shell">动手写第一个 shell</h2>
<h3 id="编辑器与编译器">编辑器与编译器</h3>
<ul>
<li>shell 程序是文本格式的，只要是文本编辑器都可以。但是因为我们的 shell 是要在 Linux 系统下运行的，所以换行符必须是<code>\n</code>，而 Windows 下的换行符是<code>\r\n</code>，因此 Windows 中的编辑器写的 shell 不能在 Linux 下运行。</li>
<li>编译器不涉及，因为 shell 是解释性语言，直接编辑完就可以运行。</li>
</ul>
<h3 id="shell-程序运行的运行的三种方法">shell 程序运行的运行的三种方法</h3>
<ul>
<li><code>./xx.sh</code>，和运行二进制可执行程序方法一样。这样运行 shell 要求 shell 程序必须具有可执行权限。<code>chmod a+x xx.sh</code> 来添加可执行权限。</li>
<li><code>source xx.sh</code>，<code>source</code> 是 Linux 的一个命令，这个命令就是用来执行脚本程序的。这样运行不需要脚本具有可执行权限。</li>
<li><code>bash xx.sh</code>，<code>bash</code> 是一个脚本程序解释器，本质上是一个可执行程序。这样执行相当于我们执行了 <code>bash</code> 程序，然后把 <code>xx.sh</code> 作为 <code>argv[1]</code> 传给他运行。</li>
</ul>
<h3 id="hello-world-程序和解释">hello world 程序和解释</h3>
<ul>
<li>shell 程序的第一行一般都是以<code>#!/bin/sh</code>开始，这行话的意思就是指定 shell 程序执行时被哪个解释器解释执行。所以我们这里写上<code>/bin/sh</code>意思就是这个<code>shell</code>将来被当前机器中<code>/bin</code>目录下的<code>sh</code>可执行程序执行。可以将第一行写为<code>#!/bin/bash</code>来指定使用<code>bash</code>执行该脚本。</li>
<li>脚本中的注释使用<code>#</code>，<code>#</code>开头的行是注释行。如果有多行需要注释，每行前面都要加<code>#</code>。（<code>#</code>就相当于是 C 语言中的<code>//</code>）;</li>
<li>shell 程序的正文，由很多行 shell 语句构成。</li>
</ul>
<h2 id="shell-语法">shell 语法</h2>
<p>shell 就是把以前命令行中键入执行的命令写成了程序。shell 其实就是为了避免反复的在命令行下手工输入而发明的一种把手工输入步骤记录下来，然后通过执行 shell 脚本程序就能再次复述原来记录的手工输入过程的一种技术。</p>
<h3 id="shell-中的变量定义和引用">shell 中的变量定义和引用</h3>
<ul>
<li>变量定义和初始化。shell 是弱类型语言（语言中的变量如果有明确的类型则属于强类型语言；变量没有明确类型就是弱类型语言），和 C 语言不同。在 shell 编程中定义变量不需要制定类型，也没有类型这个概念。</li>
<li>变量定义时可以初始化，使用<code>=</code>进行初始化赋值。在 shell 中赋值的=两边是不能有空格的。
注意：shell 对语法非常在意，非常严格。很多地方空格都是必须没有或者必须有，而且不能随意有没有空格。</li>
<li>变量赋值，变量定义后可以再次赋值，新的赋值会覆盖老的赋值。shell 中并不刻意区分变量的定义和赋值，反正每个变量就是一个符号，这个符号的值就是最后一个给他赋值时的值。</li>
<li>变量引用。shell 中引用一个变量必须使用<code>$</code>符号，<code>$</code>符号就是变量解引用符号。</li>
</ul>
<p>注意：<code>$</code>符号后面跟一个字符串，这个字符串就会被当作变量去解析。如果这个字符串本身没有定义，执行时并不会报错，而是把这个变量解析为空。也就是说在 shell 中没有被定义的变量其实就相当于是一个定义并赋值为空的变量。</p>
<p>注意：变量引用的时候可以<code>$var</code>，也可以<code>${var}</code>。这两种的区别是在某些情况下只能用<code>${var}</code>而不能简单的<code>$var</code>。</p>
<h3 id="shell-中无引用单引号和双引号的区别">shell 中无引用、单引号和双引号的区别</h3>
<ul>
<li>shell 中使用字符串可以不加双引号，直接使用。而且有空格时也可以，但是缺陷是不能输出<code>&quot;</code>或者其他转义字符。</li>
<li>shell 中也可以使用单引号来表示字符串，也是直接使用的，不能输出转义字符。</li>
<li>单引号中：完全字面替换（不可包含单引号本身）</li>
<li>双引号中：
<ul>
<li><code>$</code>加变量名可以取变量的值</li>
<li>反引号仍表示命令替换</li>
<li><code>\$</code>表示<code>$</code>的字面值（输出$符号）</li>
<li>`表示`的字面值</li>
<li><code>\&quot;</code>表示<code>&quot;</code>的字面值</li>
<li><code>\\</code>表示<code>\</code>的字面值</li>
</ul>
</li>
</ul>
<p>除以上情况之外，在其它字符前面的\无特殊含义，只表示字面值。</p>
<p>单引号会原样输出，双引号可以调用命令：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nv">PATH_A</span><span class="o">=</span><span class="s2">&#34;`pwd`/include&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">PATH_B</span><span class="o">=</span><span class="s1">&#39;`pwd`/include&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="nv">$PATH_A</span>
</span></span><span class="line"><span class="cl"><span class="c1"># /home/a/b/include</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="nv">$PATH_B</span>
</span></span><span class="line"><span class="cl"><span class="c1"># `pwd`/include</span>
</span></span></code></pre></div><h3 id="shell-中调用-linux-命令">shell 中调用 Linux 命令</h3>
<ul>
<li>直接执行</li>
<li>反引号括起来执行。有时候我们在 shell 中调用 Linux 命令是为了得到这个命令的返回值（结果值），这时候就适合用一对反引号 (键盘上 ESC 按键下面的那个按键，和<code>~</code>在一个按键上) 来调用执行命令。</li>
</ul>
<h3 id="shell-中的选择分支结构">shell 中的选择分支结构</h3>
<ul>
<li>shell 的 <code>if</code> 语言用法很多，在此只介绍常用的，其他感兴趣可以自己去学</li>
</ul>
<p>典型<code>if</code>语言格式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> 表达式 <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">  xxx
</span></span><span class="line"><span class="cl">  yyy
</span></span><span class="line"><span class="cl">  zzz
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl">  xxx
</span></span><span class="line"><span class="cl">  ddd
</span></span><span class="line"><span class="cl">  uuu
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span></code></pre></div><h4 id="if-的典型应用">if 的典型应用</h4>
<ul>
<li>
<p><code>-f</code>判断文件是否存在，注意<code>[]</code>里面<strong>前后都有空格</strong>，不能省略</p>
</li>
<li>
<p><code>-d</code>判断目录是否存在</p>
</li>
<li>
<p><code>&quot;str1&quot; = &quot;str2&quot;</code>判断字符串是否相等，注意<strong>用一个等号而不是两个</strong></p>
</li>
<li>
<p>判断数字是否相等</p>
<ul>
<li><code>-eq</code>等于</li>
<li><code>-gt</code>大于</li>
<li><code>-lt</code>小于</li>
<li><code>-ge</code>大于等于</li>
<li><code>-le</code>小于等于</li>
</ul>
</li>
<li>
<p><code>-z</code>判断字符串是否为空，注意<code>-z</code>判断时如果变量本身没定义也是不成立（也就是说-z 认为没定义不等于为空）</p>
</li>
<li>
<p><code>-o</code>表示逻辑或，连接两个表达式</p>
<ul>
<li><code>if [ 10 -eq 10 -o  ]; then</code></li>
</ul>
</li>
<li>
<p><code>&amp;&amp;</code> <code>||</code>表示逻辑与和逻辑或</p>
</li>
</ul>
<h3 id="shell-中的循环结构">shell 中的循环结构</h3>
<p><code>for</code> 循环，要求能看懂、能改即可。不要求能够完全不参考写出来。因为毕竟嵌入式并不需要完全重新手写。</p>
<p><code>while</code> 循环，和 C 语言的循环在逻辑上无差别，要注意很多格式要求，譬如：<code>while</code> 后面的 <code>[]</code> 两边都有空格，<code>[]</code> 后面有分号（如果 do 放在一行的话），<code>i++</code>的写法中有两层括号。</p>
<h3 id="echo-的创建和追加输入文件">echo 的创建和追加输入文件</h3>
<ul>
<li>在 shell 中可以直接使用 <code>echo</code> 指令新建一个文件，并且将一些内容传入这个文件中。创建文件并输入内容的关键就是<code>&gt;</code>。</li>
<li>还可以使用 <code>echo</code> 指令配合追加符号<code>&gt;&gt;</code> 向一个已经存在的文件末尾追加输入内容。</li>
</ul>
<h3 id="shell-中其他值得关注的知识点">shell 中其他值得关注的知识点</h3>
<h4 id="case-语句">case 语句</h4>
<ul>
<li>shell 中的 case 语句和 C 语言中的 switch case 语句作用一样，格式有差异</li>
<li>shell 中的 case 语句天生没有 <code>break</code>，也不需要<code>break</code>，和 C 语言中的 switch case 不同。shell 中的 case 默认就是匹配上哪个执行哪个，不会说执行完了还去执行后面的其他 case</li>
</ul>
<h4 id="调用-shell-程序的传参">调用 shell 程序的传参</h4>
<ul>
<li>C 语言中可以通过 <code>main</code> 函数的 <code>argc</code> 和 <code>argv</code> 给程序传参</li>
<li>shell 程序本身也可以在调用时传参给他。在 shell 程序内部使用传参也是使用的一些特定符号来表示的，包括：
<ul>
<li><code>$#</code>表示调用该 shell 时传参的个数。（<code>$#</code>计数时只考虑真正的参数个数）</li>
<li><code>$0、$1、$2·····</code>则依次表示传参的各个参数</li>
</ul>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./a.out aa bb cc     
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># argc = 4</span>
</span></span><span class="line"><span class="cl"><span class="c1"># argv[0] = ./a.out</span>
</span></span><span class="line"><span class="cl"><span class="c1"># argv[1] 是第一个有效参数····</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">source</span> a.sh aa bb cc  
</span></span><span class="line"><span class="cl"><span class="c1"># $# = 3</span>
</span></span><span class="line"><span class="cl"><span class="c1"># $0是执行这个 shell 程序的解析程序的名字</span>
</span></span><span class="line"><span class="cl"><span class="c1"># $1是第一个有效参数的值</span>
</span></span><span class="line"><span class="cl"><span class="c1"># $2是第 2 个有效参数的值·····</span>
</span></span></code></pre></div><h4 id="while-循环和-case-语言和传参结合">while 循环和 case 语言和传参结合</h4>
<ul>
<li>shell 中的 <code>break</code> 关键字和 <code>C</code> 语言中意义相同（都是跳出）但是用法不同。因为 shell 中 <code>case</code> 语句默认不用 <code>break</code> 的，因此在 <code>shell</code> 中 <code>break</code> 只用于循环跳出。所以当 <code>while</code> 中内嵌 <code>case</code> 语句时，<code>case</code> 中的 <code>break</code> 是跳出外层的 <code>while</code> 循环的，不是用来跳出 <code>case</code> 语句的。</li>
<li>shell 中的<code>$# $1</code>等内置变量的值是可以被改变，被 <code>shift</code> 指令改变。<code>shift</code> 指令有点像左移运算符，把我们给 shell 程序的传参左移了一个移出去了，原来的<code>$2</code>变成了新的<code>$1</code>，原来的<code>$#</code>少了 1 个。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-chattr 修改文件与目录属性防止误删除</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-chattr%E4%BF%AE%E6%94%B9%E6%96%87%E4%BB%B6%E4%B8%8E%E7%9B%AE%E5%BD%95%E5%B1%9E%E6%80%A7%E9%98%B2%E6%AD%A2%E8%AF%AF%E5%88%A0%E9%99%A4/</link>
      <pubDate>Sun, 25 Sep 2022 11:20:35 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-chattr%E4%BF%AE%E6%94%B9%E6%96%87%E4%BB%B6%E4%B8%8E%E7%9B%AE%E5%BD%95%E5%B1%9E%E6%80%A7%E9%98%B2%E6%AD%A2%E8%AF%AF%E5%88%A0%E9%99%A4/</guid>
      <description>&lt;h2 id=&#34;使用背景&#34;&gt;使用背景&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;chattr&lt;/code&gt;命令可以修改 Linux 的文件属性，在类 Unix 等发行版中，该命令能够有效防止文件和目录被意外的删除或修改。文件在 Linux 中被描述为一个数据结构，&lt;code&gt;chattr&lt;/code&gt; 命令在大多数现代 Linux 操作系统中是可用的，可以修改文件属性，一旦定义文件的隐藏属性，那么&lt;strong&gt;该文件的拥有者和 root 用户也无权操作该文件&lt;/strong&gt;，只能解除文件的隐藏属性。这就可以有效的避免被误删除。&lt;/p&gt;
&lt;h2 id=&#34;命令格式&#34;&gt;命令格式&lt;/h2&gt;
&lt;p&gt;一个完整的命令一般由命令 (chattr)，可选项 (option)，操作符 (operator) 与属性 (attribute) 组成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chattr &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;option&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;operator&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;attribute&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;  file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;[option] 可选项：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-R， 递归更改目录及其内容的属性。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-V， 详细说明chattr的输出并打印程序版本。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-f， 隐藏大多数错误消息。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;[operator] 操作符：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+，追加指定属性到文件已存在属性中
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-， &lt;span class=&#34;nv&#34;&gt;删除指定属性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;，直接设置文件属性为指定属性
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;[attribute] 属性如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a， 只能向文件中添加数据
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;A，不更新文件或目录的最后访问时间
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;i， 文件或目录不可改变
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;h3 id=&#34;lsattr-命令检查文件已有属性&#34;&gt;lsattr 命令检查文件已有属性&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-d：如果目标是目录，只会列出目录本身的隐藏属性，而不会列出所含文件或子目录的隐藏属性信息
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-R：作用于目录时，会显示所有的子目录和文件的隐藏信息
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ lsattr clash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/glados.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/clash-linux-386-v1.10.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/Country.mmdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/cache.db
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/clash-linux-amd64-v1.10.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ lsattr -d clash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ lsattr -R clash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/glados.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/clash-linux-386-v1.10.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/Country.mmdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/cache.db
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/clash-linux-amd64-v1.10.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;clash/dashboard:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/manifest.webmanifest
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/assets
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;clash/dashboard/assets:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/assets/logo.b453e72f.png
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/assets/index.408383.js
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/assets/index.966f8a.css
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/assets/vendor.ca5569.js
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/sw.js
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/workbox-7ce28d.js
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e------- clash/dashboard/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;禁止对文件testmd重命名移动或删除也不能修改其内容&#34;&gt;禁止对文件&lt;code&gt;test.md&lt;/code&gt;重命名，移动或删除，也不能修改其内容&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo chattr +i test.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;尝试修改该文件，将会被拒绝：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ rm -f ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm: cannot remove &lt;span class=&#34;s1&#34;&gt;&amp;#39;./test.md&amp;#39;&lt;/span&gt;: Operation not permitted
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Hello World!&amp;#39;&lt;/span&gt; &amp;gt; test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bash: ./test.md: Operation not permitted
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ mv ./test.md ./fileDir
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv: cannot move &lt;span class=&#34;s1&#34;&gt;&amp;#39;./test.md&amp;#39;&lt;/span&gt; to &lt;span class=&#34;s1&#34;&gt;&amp;#39;./fileDir/test.md&amp;#39;&lt;/span&gt;: Operation not permitted
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;禁止修改文件夹filedir及文件夹中的数据&#34;&gt;禁止修改文件夹&lt;code&gt;fileDir&lt;/code&gt;及文件夹中的数据&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir ./fileDir &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; touch ./fileDir/test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo chattr +i -R ./fileDir
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;尝试修改文件夹中的内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ rm -rf ./fileDir
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm: cannot remove &lt;span class=&#34;s1&#34;&gt;&amp;#39;./fileDir/test.md&amp;#39;&lt;/span&gt;: Operation not permitted
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;允许向文件添加内容禁止修改或删除内容禁止移动文件&#34;&gt;允许向文件添加内容，禁止修改或删除内容，禁止移动文件&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo chattr +a ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ lsattr ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-----a--------e--- ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World!&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; ./test.md   &lt;span class=&#34;c1&#34;&gt;# 追加内容 OK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&amp;gt; ./test.md            &lt;span class=&#34;c1&#34;&gt;# 修改内容 NO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bash: ./test.md: Operation not permitted
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;只允许在目录filedir中建立和修改文件但是禁止删除移动文件&#34;&gt;只允许在目录&lt;code&gt;fileDir&lt;/code&gt;中建立和修改文件，但是禁止删除、移动文件&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo chattr +a ./fileDir
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;取消某个属性&#34;&gt;取消某个属性&lt;/h3&gt;
&lt;p&gt;使用&lt;code&gt;-&lt;/code&gt;操作符即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 先给文件添加属性a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo chattr +a ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ lsattr ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-----a--------e--- ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 取消属性a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ sudo chattr -a ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ lsattr ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--------------e--- ./test.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="使用背景">使用背景</h2>
<p><code>chattr</code>命令可以修改 Linux 的文件属性，在类 Unix 等发行版中，该命令能够有效防止文件和目录被意外的删除或修改。文件在 Linux 中被描述为一个数据结构，<code>chattr</code> 命令在大多数现代 Linux 操作系统中是可用的，可以修改文件属性，一旦定义文件的隐藏属性，那么<strong>该文件的拥有者和 root 用户也无权操作该文件</strong>，只能解除文件的隐藏属性。这就可以有效的避免被误删除。</p>
<h2 id="命令格式">命令格式</h2>
<p>一个完整的命令一般由命令 (chattr)，可选项 (option)，操作符 (operator) 与属性 (attribute) 组成：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">chattr <span class="o">[</span>option<span class="o">]</span> <span class="o">[</span>operator<span class="o">]</span> <span class="o">[</span>attribute<span class="o">]</span>  file
</span></span></code></pre></div><p>[option] 可选项：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">-R， 递归更改目录及其内容的属性。
</span></span><span class="line"><span class="cl">-V， 详细说明chattr的输出并打印程序版本。
</span></span><span class="line"><span class="cl">-f， 隐藏大多数错误消息。
</span></span></code></pre></div><p>[operator] 操作符：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">+，追加指定属性到文件已存在属性中
</span></span><span class="line"><span class="cl">-， <span class="nv">删除指定属性</span>
</span></span><span class="line"><span class="cl"><span class="o">=</span>，直接设置文件属性为指定属性
</span></span></code></pre></div><p>[attribute] 属性如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">a， 只能向文件中添加数据
</span></span><span class="line"><span class="cl">A，不更新文件或目录的最后访问时间
</span></span><span class="line"><span class="cl">i， 文件或目录不可改变
</span></span></code></pre></div><h2 id="使用实例">使用实例</h2>
<h3 id="lsattr-命令检查文件已有属性">lsattr 命令检查文件已有属性</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">-d：如果目标是目录，只会列出目录本身的隐藏属性，而不会列出所含文件或子目录的隐藏属性信息
</span></span><span class="line"><span class="cl">-R：作用于目录时，会显示所有的子目录和文件的隐藏信息
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ lsattr clash
</span></span><span class="line"><span class="cl">--------------e------- clash/glados.yaml
</span></span><span class="line"><span class="cl">--------------e------- clash/clash-linux-386-v1.10.0
</span></span><span class="line"><span class="cl">--------------e------- clash/Country.mmdb
</span></span><span class="line"><span class="cl">--------------e------- clash/cache.db
</span></span><span class="line"><span class="cl">--------------e------- clash/clash-linux-amd64-v1.10.0
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard
</span></span><span class="line"><span class="cl">$ lsattr -d clash
</span></span><span class="line"><span class="cl">--------------e------- clash
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ lsattr -R clash
</span></span><span class="line"><span class="cl">--------------e------- clash/glados.yaml
</span></span><span class="line"><span class="cl">--------------e------- clash/clash-linux-386-v1.10.0
</span></span><span class="line"><span class="cl">--------------e------- clash/Country.mmdb
</span></span><span class="line"><span class="cl">--------------e------- clash/cache.db
</span></span><span class="line"><span class="cl">--------------e------- clash/clash-linux-amd64-v1.10.0
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">clash/dashboard:
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/manifest.webmanifest
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/assets
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">clash/dashboard/assets:
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/assets/logo.b453e72f.png
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/assets/index.408383.js
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/assets/index.966f8a.css
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/assets/vendor.ca5569.js
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/sw.js
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/workbox-7ce28d.js
</span></span><span class="line"><span class="cl">--------------e------- clash/dashboard/index.html
</span></span></code></pre></div><h3 id="禁止对文件testmd重命名移动或删除也不能修改其内容">禁止对文件<code>test.md</code>重命名，移动或删除，也不能修改其内容</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo chattr +i test.md
</span></span></code></pre></div><p>尝试修改该文件，将会被拒绝：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ rm -f ./test.md
</span></span><span class="line"><span class="cl">rm: cannot remove <span class="s1">&#39;./test.md&#39;</span>: Operation not permitted
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ <span class="nb">echo</span> <span class="s1">&#39;Hello World!&#39;</span> &gt; test.md
</span></span><span class="line"><span class="cl">bash: ./test.md: Operation not permitted
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ mv ./test.md ./fileDir
</span></span><span class="line"><span class="cl">mv: cannot move <span class="s1">&#39;./test.md&#39;</span> to <span class="s1">&#39;./fileDir/test.md&#39;</span>: Operation not permitted
</span></span></code></pre></div><h3 id="禁止修改文件夹filedir及文件夹中的数据">禁止修改文件夹<code>fileDir</code>及文件夹中的数据</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir ./fileDir <span class="o">&amp;&amp;</span> touch ./fileDir/test.md
</span></span><span class="line"><span class="cl">sudo chattr +i -R ./fileDir
</span></span></code></pre></div><p>尝试修改文件夹中的内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ rm -rf ./fileDir
</span></span><span class="line"><span class="cl">rm: cannot remove <span class="s1">&#39;./fileDir/test.md&#39;</span>: Operation not permitted
</span></span></code></pre></div><h3 id="允许向文件添加内容禁止修改或删除内容禁止移动文件">允许向文件添加内容，禁止修改或删除内容，禁止移动文件</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ sudo chattr +a ./test.md
</span></span><span class="line"><span class="cl">$ lsattr ./test.md
</span></span><span class="line"><span class="cl">-----a--------e--- ./test.md
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ <span class="nb">echo</span> <span class="s2">&#34;Hello World!&#34;</span> &gt;&gt; ./test.md   <span class="c1"># 追加内容 OK</span>
</span></span><span class="line"><span class="cl">$ <span class="nb">echo</span> <span class="s2">&#34;hello&#34;</span>&gt; ./test.md            <span class="c1"># 修改内容 NO</span>
</span></span><span class="line"><span class="cl">bash: ./test.md: Operation not permitted
</span></span></code></pre></div><h3 id="只允许在目录filedir中建立和修改文件但是禁止删除移动文件">只允许在目录<code>fileDir</code>中建立和修改文件，但是禁止删除、移动文件</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo chattr +a ./fileDir
</span></span></code></pre></div><h3 id="取消某个属性">取消某个属性</h3>
<p>使用<code>-</code>操作符即可：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 先给文件添加属性a</span>
</span></span><span class="line"><span class="cl">$ sudo chattr +a ./test.md
</span></span><span class="line"><span class="cl">$ lsattr ./test.md
</span></span><span class="line"><span class="cl">-----a--------e--- ./test.md
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 取消属性a</span>
</span></span><span class="line"><span class="cl">$ sudo chattr -a ./test.md
</span></span><span class="line"><span class="cl">$ lsattr ./test.md
</span></span><span class="line"><span class="cl">--------------e--- ./test.md
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>解决 Linux 终端回车键变成字符 M</title>
      <link>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3linux%E7%BB%88%E7%AB%AF%E5%9B%9E%E8%BD%A6%E9%94%AE%E5%8F%98%E6%88%90%E5%AD%97%E7%AC%A6m/</link>
      <pubDate>Mon, 12 Sep 2022 14:52:12 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3linux%E7%BB%88%E7%AB%AF%E5%9B%9E%E8%BD%A6%E9%94%AE%E5%8F%98%E6%88%90%E5%AD%97%E7%AC%A6m/</guid>
      <description>&lt;h2 id=&#34;保留现场&#34;&gt;保留现场&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/14-49-58-a6e2e264bfab205e0838ad8e49adec81-20220912144956-12eead.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/14-49-58-a6e2e264bfab205e0838ad8e49adec81-20220912144956-12eead.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;解决方法&#34;&gt;解决方法&lt;/h2&gt;
&lt;p&gt;命令行执行&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;stty sane
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="保留现场">保留现场</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/14-49-58-a6e2e264bfab205e0838ad8e49adec81-20220912144956-12eead.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/14-49-58-a6e2e264bfab205e0838ad8e49adec81-20220912144956-12eead.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="解决方法">解决方法</h2>
<p>命令行执行</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">stty sane
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Linux 下切换 Python 版本</title>
      <link>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3linux%E4%B8%8B%E5%88%87%E6%8D%A2python%E7%89%88%E6%9C%AC/</link>
      <pubDate>Mon, 12 Sep 2022 14:05:17 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3linux%E4%B8%8B%E5%88%87%E6%8D%A2python%E7%89%88%E6%9C%AC/</guid>
      <description>&lt;h2 id=&#34;需求背景&#34;&gt;需求背景&lt;/h2&gt;
&lt;p&gt;用过 Python 的都知道，Python 是不向后兼容的，也就是 Python3.X 开发的程序，使用 Python2.X 环境就无法正常运行。因为很多语法都改变了。现在接触到的大部分 Python 程序都是 Python3.X 开发的，但是偶尔也会遇到使用 Python2.X 的时候。这就需要灵活切换版本。&lt;/p&gt;
&lt;p&gt;一般 Linux 的各个发行版都预装了 Python2.X。我使用的 Debian 就预装了 Python2.7。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ python -V
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Python 2.7.16
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是我同时也安装了 Python3.7&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ls /usr/bin &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;python*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dh_python2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python2.7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3.7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3.7m
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;alias-修改别名&#34;&gt;alias 修改别名&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;python&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/bin/python3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ python -V
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Python 3.7.3  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的别名修改只对当前终端有效。如果要使每个窗口都使用这个别名，将别名加入&lt;code&gt;~/.bashrc&lt;/code&gt;，如 zsh 是则是&lt;code&gt;~/.zshrc&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;软链接&#34;&gt;软链接&lt;/h2&gt;
&lt;p&gt;和修改别名类似&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ln -s python /usr/bin/python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;update-alternatives&#34;&gt;update-alternatives&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;update-alternatives&lt;/code&gt;是 Debian 系统提供的一个工具，Ubuntu 是基于 Debian 的，所以 Ubuntu 也可以使用，其他发行版没有该工具。它可以用来方便快捷地切换应用版本，不仅仅用来切换 Python，其他应用程序有多个版本的也可以使用该工具。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;update-alternatives&lt;/code&gt;本质也是建立软链接，只不过有了统一的管理，首先我们需要使用&lt;code&gt;--install&lt;/code&gt;参数，添加一些候选项，也就是执行&lt;code&gt;python&lt;/code&gt;这个命令时，它可以有哪些选择，在这里就是&lt;code&gt;python3.7.3&lt;/code&gt;和&lt;code&gt;python2.7.16&lt;/code&gt;两个选择。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# --install &amp;lt;链接&amp;gt; &amp;lt;名称&amp;gt; &amp;lt;路径&amp;gt; &amp;lt;优先级&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.7 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;，这里的&lt;code&gt;/usr/bin/python&lt;/code&gt;链接文件，两个可选项必须是一样的，这样这个链接文件才可以选择两个不同的可选项去链接。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;python&lt;/code&gt;是在命令行执行的命令。&lt;code&gt;/usr/bin/python2.7&lt;/code&gt;是执行&lt;code&gt;python&lt;/code&gt;命令后调用具体哪个版本。最后的数字&lt;code&gt;2&lt;/code&gt;是优先级，也就是&lt;code&gt;python2.7&lt;/code&gt;比&lt;code&gt;python3.7&lt;/code&gt;优先级高，如果不指定版本，那么默认就是使用&lt;code&gt;python2&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;我们再查看一下版本信息，发现是&lt;code&gt;python2.7.16&lt;/code&gt;。说明是默认版本。并且&lt;code&gt;python&lt;/code&gt;已被链接到我们管理的软链接上。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ python -V
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Python 2.7.16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ll /usr/bin  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;python&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lrwxrwxrwx &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root   python -&amp;gt; /etc/alternatives/python
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看&lt;code&gt;python&lt;/code&gt;的可选配置，可以看到有两个可选配置，默认是&lt;code&gt;python2&lt;/code&gt;，第一列是序号，如果我们想切换到&lt;code&gt;python3&lt;/code&gt;，对应的数字&lt;code&gt;2&lt;/code&gt;即可。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root at RISCX in ~
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ update-alternatives --config python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;There are &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; choices &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; the alternative python &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;providing /usr/bin/python&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Selection    Path                Priority   Status
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;* &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;            /usr/bin/python2.7   &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;         auto mode
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;            /usr/bin/python2.7   &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;         manual mode
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;            /usr/bin/python3.7   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;         manual mode
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Press &amp;lt;enter&amp;gt; to keep the current choice&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;*&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;, or &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; selection number:2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;update-alternatives: using /usr/bin/python3.7 to provide /usr/bin/python &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;python&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; in manual mode
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再次查看版本信息，发现已经切换成功。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ python -V
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Python 3.7.3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;执行&lt;code&gt;update-alternatives&lt;/code&gt;经常会导致我的终端&lt;strong&gt;回车失效&lt;/strong&gt;，可以参考&lt;a href=&#34;https://dunky-z.github.io/2022/09/12/%E8%A7%A3%E5%86%B3Linux%E7%BB%88%E7%AB%AF%E5%9B%9E%E8%BD%A6%E9%94%AE%E5%8F%98%E6%88%90%E5%AD%97%E7%AC%A6M/&#34;&gt;解决 Linux 终端回车键变成字符 M&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;--remove&lt;/code&gt;，删除可选项：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo update-alternatives --remove python /usr/bin/python2.7
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="需求背景">需求背景</h2>
<p>用过 Python 的都知道，Python 是不向后兼容的，也就是 Python3.X 开发的程序，使用 Python2.X 环境就无法正常运行。因为很多语法都改变了。现在接触到的大部分 Python 程序都是 Python3.X 开发的，但是偶尔也会遇到使用 Python2.X 的时候。这就需要灵活切换版本。</p>
<p>一般 Linux 的各个发行版都预装了 Python2.X。我使用的 Debian 就预装了 Python2.7。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python -V
</span></span><span class="line"><span class="cl">Python 2.7.16
</span></span></code></pre></div><p>但是我同时也安装了 Python3.7</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ ls /usr/bin <span class="p">|</span> grep <span class="s2">&#34;python*&#34;</span>
</span></span><span class="line"><span class="cl">dh_python2
</span></span><span class="line"><span class="cl">python
</span></span><span class="line"><span class="cl">python2
</span></span><span class="line"><span class="cl">python2.7
</span></span><span class="line"><span class="cl">python3
</span></span><span class="line"><span class="cl">python3.7
</span></span><span class="line"><span class="cl">python3.7m
</span></span><span class="line"><span class="cl">python3m
</span></span></code></pre></div><h2 id="alias-修改别名">alias 修改别名</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ <span class="nb">alias</span> <span class="nv">python</span><span class="o">=</span>/usr/bin/python3
</span></span><span class="line"><span class="cl">$ python -V
</span></span><span class="line"><span class="cl">Python 3.7.3  
</span></span></code></pre></div><p>上面的别名修改只对当前终端有效。如果要使每个窗口都使用这个别名，将别名加入<code>~/.bashrc</code>，如 zsh 是则是<code>~/.zshrc</code>。</p>
<h2 id="软链接">软链接</h2>
<p>和修改别名类似</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ln -s python /usr/bin/python3
</span></span></code></pre></div><h2 id="update-alternatives">update-alternatives</h2>
<p><code>update-alternatives</code>是 Debian 系统提供的一个工具，Ubuntu 是基于 Debian 的，所以 Ubuntu 也可以使用，其他发行版没有该工具。它可以用来方便快捷地切换应用版本，不仅仅用来切换 Python，其他应用程序有多个版本的也可以使用该工具。</p>
<p><code>update-alternatives</code>本质也是建立软链接，只不过有了统一的管理，首先我们需要使用<code>--install</code>参数，添加一些候选项，也就是执行<code>python</code>这个命令时，它可以有哪些选择，在这里就是<code>python3.7.3</code>和<code>python2.7.16</code>两个选择。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># --install &lt;链接&gt; &lt;名称&gt; &lt;路径&gt; &lt;优先级&gt;</span>
</span></span><span class="line"><span class="cl">sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 <span class="m">2</span>
</span></span><span class="line"><span class="cl">sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.7 <span class="m">1</span>
</span></span></code></pre></div><p><strong>注意</strong>，这里的<code>/usr/bin/python</code>链接文件，两个可选项必须是一样的，这样这个链接文件才可以选择两个不同的可选项去链接。</p>
<p><code>python</code>是在命令行执行的命令。<code>/usr/bin/python2.7</code>是执行<code>python</code>命令后调用具体哪个版本。最后的数字<code>2</code>是优先级，也就是<code>python2.7</code>比<code>python3.7</code>优先级高，如果不指定版本，那么默认就是使用<code>python2</code>。</p>
<p>我们再查看一下版本信息，发现是<code>python2.7.16</code>。说明是默认版本。并且<code>python</code>已被链接到我们管理的软链接上。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python -V
</span></span><span class="line"><span class="cl">Python 2.7.16
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ ll /usr/bin  <span class="p">|</span> grep <span class="s2">&#34;python&#34;</span>
</span></span><span class="line"><span class="cl">lrwxrwxrwx <span class="m">1</span> root   python -&gt; /etc/alternatives/python
</span></span></code></pre></div><p>查看<code>python</code>的可选配置，可以看到有两个可选配置，默认是<code>python2</code>，第一列是序号，如果我们想切换到<code>python3</code>，对应的数字<code>2</code>即可。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">root at RISCX in ~
</span></span><span class="line"><span class="cl">$ update-alternatives --config python
</span></span><span class="line"><span class="cl">There are <span class="m">2</span> choices <span class="k">for</span> the alternative python <span class="o">(</span>providing /usr/bin/python<span class="o">)</span>.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Selection    Path                Priority   Status
</span></span><span class="line"><span class="cl">------------------------------------------------------------
</span></span><span class="line"><span class="cl">* <span class="m">0</span>            /usr/bin/python2.7   <span class="m">2</span>         auto mode
</span></span><span class="line"><span class="cl">  <span class="m">1</span>            /usr/bin/python2.7   <span class="m">2</span>         manual mode
</span></span><span class="line"><span class="cl">  <span class="m">2</span>            /usr/bin/python3.7   <span class="m">1</span>         manual mode
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Press &lt;enter&gt; to keep the current choice<span class="o">[</span>*<span class="o">]</span>, or <span class="nb">type</span> selection number:2
</span></span><span class="line"><span class="cl">update-alternatives: using /usr/bin/python3.7 to provide /usr/bin/python <span class="o">(</span>python<span class="o">)</span> in manual mode
</span></span></code></pre></div><p>再次查看版本信息，发现已经切换成功。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python -V
</span></span><span class="line"><span class="cl">Python 3.7.3
</span></span></code></pre></div><blockquote>
<p>执行<code>update-alternatives</code>经常会导致我的终端<strong>回车失效</strong>，可以参考<a href="https://dunky-z.github.io/2022/09/12/%E8%A7%A3%E5%86%B3Linux%E7%BB%88%E7%AB%AF%E5%9B%9E%E8%BD%A6%E9%94%AE%E5%8F%98%E6%88%90%E5%AD%97%E7%AC%A6M/">解决 Linux 终端回车键变成字符 M</a></p>
</blockquote>
<p><code>--remove</code>，删除可选项：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo update-alternatives --remove python /usr/bin/python2.7
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-nohup 后台运行</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-nohup%E5%90%8E%E5%8F%B0%E8%BF%90%E8%A1%8C/</link>
      <pubDate>Sat, 10 Sep 2022 17:14:58 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-nohup%E5%90%8E%E5%8F%B0%E8%BF%90%E8%A1%8C/</guid>
      <description>&lt;p&gt;使用 MobaXertm 连接服务器后，想要在运行一个下载任务，使用&lt;code&gt;&amp;amp;&lt;/code&gt;挂在后台后，退出 MobaXterm，后台的任务也随之中断，于是搜到这个&lt;code&gt;nohup&lt;/code&gt;命令，可以完成我的需求。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nohup&lt;/code&gt;意思是 No Hang Up，不要挂起的意思，即使退出终端也不会中断任务。&lt;/p&gt;
&lt;p&gt;为了方便以后查阅，这里总结一下关于后台运行相关的命令。首先是最常用的&lt;code&gt;&amp;amp;&lt;/code&gt;符号。&lt;/p&gt;
&lt;h2 id=&#34;-后台运行&#34;&gt;&amp;amp; 后台运行&lt;/h2&gt;
&lt;p&gt;比如执行编译任务时通常会占用终端前台，这时候无法再执行其他命令，除非再开一个终端，对于有 GUI 界面时，再开一个终端很方便，但是如果是服务器就只能再想办法了。 &lt;code&gt;&amp;amp;&lt;/code&gt;可以将命令执行过程放在后台运行，如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ make  &amp;gt;  make.log  2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16586&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; 是将标准出错重定向到标准输出，这里的标准输出已经重定向到了&lt;code&gt;make.log&lt;/code&gt;文件，即将标准出错也输出到&lt;code&gt;make.log&lt;/code&gt;文件中。最后一个&lt;code&gt;&amp;amp;&lt;/code&gt;，是让该命令在后台执行。
试想&lt;code&gt;2&amp;gt;1&lt;/code&gt;代表什么，&lt;code&gt;2&lt;/code&gt;与&lt;code&gt;&amp;gt;&lt;/code&gt;结合代表错误重定向，而&lt;code&gt;1&lt;/code&gt;则代表错误重定向到一个文件&lt;code&gt;1&lt;/code&gt;，而不代表标准输出；换成&lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt;，&lt;code&gt;&amp;amp;&lt;/code&gt;与&lt;code&gt;1&lt;/code&gt;结合就代表标准输出了，就变成错误重定向到标准输出。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在后台运行&lt;code&gt;make&lt;/code&gt;进行编译，并将输出结果（错误和正常输出）都保存到&lt;code&gt;make.log&lt;/code&gt;文件中，提交任务成功后，会显示进程 ID，编译的进程 ID 为 &lt;code&gt;16586&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;有了进程 ID 我们可以监控，也可以中断进程：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 查看进程状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ps -ef &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;m&#34;&gt;16586&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 中断进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;kill&lt;/span&gt; -9 &lt;span class=&#34;m&#34;&gt;16586&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是使用 &lt;code&gt;&amp;amp;&lt;/code&gt;时关闭终端后，进程也会随之关闭。如果想要在后台持续运行程序，就需要&lt;code&gt;nohup&lt;/code&gt;命令。&lt;/p&gt;
&lt;h2 id=&#34;nohup-使用&#34;&gt;nohup 使用&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ nohup make  &amp;gt;  make.log  2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;112233&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;命令功能同上，但是终端关闭，后台程序也会继续执行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;：终端关闭，是指带 GUI 的界面里终端，如果使用 SSH 等登陆，比如使用 MobaXterm，一个 session 相当于一个登陆账户，如果异常退出了这个账户，那么后台执行的程序也会中断。如果需要继续执行，需要正常退出账户，执行&lt;code&gt;exit&lt;/code&gt;命令。&lt;/p&gt;
&lt;h2 id=&#34;汇总&#34;&gt;汇总&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;fg&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;# 将后台中的命令调至前台继续运行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;bg&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;# 将一个在后台暂停的命令，变成继续执行 (在后台执行)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;jobs&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;# 查看当前有多少在后台运行的命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;kill&lt;/span&gt; %num &lt;span class=&#34;c1&#34;&gt;# 终止进程num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;# 加在命令后可以将其置于后台运行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ctrl + z  &lt;span class=&#34;c1&#34;&gt;# 置于后台，并且暂停不可执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ctrl + c  &lt;span class=&#34;c1&#34;&gt;# 终止前台进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ctrl + &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# 退出&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ctrl + d  &lt;span class=&#34;c1&#34;&gt;# 结束当前输入(即用户不再给当前程序发出指令)，那么Linux通常将结束当前程序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>使用 MobaXertm 连接服务器后，想要在运行一个下载任务，使用<code>&amp;</code>挂在后台后，退出 MobaXterm，后台的任务也随之中断，于是搜到这个<code>nohup</code>命令，可以完成我的需求。</p>
<p><code>nohup</code>意思是 No Hang Up，不要挂起的意思，即使退出终端也不会中断任务。</p>
<p>为了方便以后查阅，这里总结一下关于后台运行相关的命令。首先是最常用的<code>&amp;</code>符号。</p>
<h2 id="-后台运行">&amp; 后台运行</h2>
<p>比如执行编译任务时通常会占用终端前台，这时候无法再执行其他命令，除非再开一个终端，对于有 GUI 界面时，再开一个终端很方便，但是如果是服务器就只能再想办法了。 <code>&amp;</code>可以将命令执行过程放在后台运行，如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ make  &gt;  make.log  2&gt;<span class="p">&amp;</span><span class="m">1</span>  <span class="p">&amp;</span> 
</span></span><span class="line"><span class="cl"><span class="o">[</span>1<span class="o">]</span> <span class="m">16586</span>
</span></span></code></pre></div><blockquote>
<p><code>2&gt;&amp;1</code> 是将标准出错重定向到标准输出，这里的标准输出已经重定向到了<code>make.log</code>文件，即将标准出错也输出到<code>make.log</code>文件中。最后一个<code>&amp;</code>，是让该命令在后台执行。
试想<code>2&gt;1</code>代表什么，<code>2</code>与<code>&gt;</code>结合代表错误重定向，而<code>1</code>则代表错误重定向到一个文件<code>1</code>，而不代表标准输出；换成<code>2&gt;&amp;1</code>，<code>&amp;</code>与<code>1</code>结合就代表标准输出了，就变成错误重定向到标准输出。</p>
</blockquote>
<p>在后台运行<code>make</code>进行编译，并将输出结果（错误和正常输出）都保存到<code>make.log</code>文件中，提交任务成功后，会显示进程 ID，编译的进程 ID 为 <code>16586</code>。</p>
<p>有了进程 ID 我们可以监控，也可以中断进程：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 查看进程状态</span>
</span></span><span class="line"><span class="cl">ps -ef <span class="p">|</span> grep <span class="m">16586</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 中断进程</span>
</span></span><span class="line"><span class="cl"><span class="nb">kill</span> -9 <span class="m">16586</span>
</span></span></code></pre></div><p>但是使用 <code>&amp;</code>时关闭终端后，进程也会随之关闭。如果想要在后台持续运行程序，就需要<code>nohup</code>命令。</p>
<h2 id="nohup-使用">nohup 使用</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">$ nohup make  &gt;  make.log  2&gt;<span class="p">&amp;</span><span class="m">1</span>  <span class="p">&amp;</span> 
</span></span><span class="line"><span class="cl"><span class="o">[</span>1<span class="o">]</span> <span class="m">112233</span>
</span></span></code></pre></div><p>命令功能同上，但是终端关闭，后台程序也会继续执行。</p>
<p><strong>NOTE</strong>：终端关闭，是指带 GUI 的界面里终端，如果使用 SSH 等登陆，比如使用 MobaXterm，一个 session 相当于一个登陆账户，如果异常退出了这个账户，那么后台执行的程序也会中断。如果需要继续执行，需要正常退出账户，执行<code>exit</code>命令。</p>
<h2 id="汇总">汇总</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">fg</span>        <span class="c1"># 将后台中的命令调至前台继续运行</span>
</span></span><span class="line"><span class="cl"><span class="nb">bg</span>        <span class="c1"># 将一个在后台暂停的命令，变成继续执行 (在后台执行)</span>
</span></span><span class="line"><span class="cl"><span class="nb">jobs</span>      <span class="c1"># 查看当前有多少在后台运行的命令</span>
</span></span><span class="line"><span class="cl"><span class="nb">kill</span> %num <span class="c1"># 终止进程num</span>
</span></span><span class="line"><span class="cl"><span class="p">&amp;</span>         <span class="c1"># 加在命令后可以将其置于后台运行</span>
</span></span><span class="line"><span class="cl">ctrl + z  <span class="c1"># 置于后台，并且暂停不可执行</span>
</span></span><span class="line"><span class="cl">ctrl + c  <span class="c1"># 终止前台进程</span>
</span></span><span class="line"><span class="cl">ctrl + <span class="se">\ </span> <span class="c1"># 退出</span>
</span></span><span class="line"><span class="cl">ctrl + d  <span class="c1"># 结束当前输入(即用户不再给当前程序发出指令)，那么Linux通常将结束当前程序</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>从零开始搭建一台 NAS 存储服务器</title>
      <link>https://lifeislife.cn/posts/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E6%90%AD%E5%BB%BA%E4%B8%80%E5%8F%B0nas%E5%AD%98%E5%82%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/</link>
      <pubDate>Sat, 10 Sep 2022 11:37:47 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B%E6%90%AD%E5%BB%BA%E4%B8%80%E5%8F%B0nas%E5%AD%98%E5%82%A8%E6%9C%8D%E5%8A%A1%E5%99%A8/</guid>
      <description>&lt;p&gt;技术没学多少，教程下满了硬盘，一直想专门部署 NAS 来存文件，但是一来要花钱，二来搭建 NAS 没有经验怕部署不好，没有现在硬盘直连舒适，所以将就用吧。&lt;/p&gt;
&lt;p&gt;自从有天忘了忘了休眠电脑，一个自动备份任务开启，在 40 度的高温天，满速跑了一天，下班回来硬盘直接报废。这就加速我折腾部署 NAS 的进程。&lt;/p&gt;
&lt;h2 id=&#34;准备阶段&#34;&gt;准备阶段&lt;/h2&gt;
&lt;p&gt;威联通的几款中意的 NAS 放购物车很久了，如果硬盘没有这么早坏掉，可能在双十一就买整机了，现在离双十一还早，硬件价格都不便宜，想来想去还是买二手硬件攒一台更划算。如果买整机，硬盘加 NAS 主机就得五千大洋，只是用来存文件，部署个 Jellyfin 看电影用，属实奢侈了。&lt;/p&gt;
&lt;p&gt;￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥&lt;/p&gt;
&lt;p&gt;买二手就得从零开始学。生命不休，折腾不止。经过一次完整的 NAS 攒机过程发现，其实 NAS 就是安装了专用系统的一台电脑而已。这个专用系统就是面向网络存储开发的，如群晖，威联通，开源的 OMV，FreeNAS 等等。&lt;/p&gt;
&lt;p&gt;既然是一台电脑，其实攒 NAS 就和攒电脑一样，选配好以下几大件即可。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU&lt;/li&gt;
&lt;li&gt;主板&lt;/li&gt;
&lt;li&gt;散热器&lt;/li&gt;
&lt;li&gt;机箱&lt;/li&gt;
&lt;li&gt;内存&lt;/li&gt;
&lt;li&gt;电源&lt;/li&gt;
&lt;li&gt;机箱风扇&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面分别介绍在攒机过程中遇到的一些概念，参数到底是什么意思。&lt;/p&gt;
&lt;h3 id=&#34;cpu&#34;&gt;CPU&lt;/h3&gt;
&lt;h4 id=&#34;cpu-型号字母数字都是什么意思&#34;&gt;CPU 型号字母数字都是什么意思&lt;/h4&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/19-03-26-07978c9e6aae76e3d1a4ac48df0521f1-20220910190326-c46d16.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/19-03-26-07978c9e6aae76e3d1a4ac48df0521f1-20220910190326-c46d16.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Intel&lt;/strong&gt; 是英特尔的英文名称，也是目前热门的 CPU 品牌；&lt;/li&gt;
&lt;li&gt;“酷睿”代表英特尔品牌下面向普通消费者的一个 CPU 系列，一般划分为 Core（酷睿）、Pentium（奔腾）、Celeron（赛扬）、Xeon（至强）、Atom（凌动）等；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;i5&lt;/strong&gt; 代表这款 CPU 定位中端，在其下面还有 i3，在其上面还有 i7 和 i9，同一代中，数字越大，性能越强；但是不同代 - 数之间，性能不能直接相比，比如 12 代的 i5 在理论性能上是强于 10 代 i7 的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;12&lt;/strong&gt; 代表这款 CPU 的代数，说明其已经发展到第十二代了，数字越大越新；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;600&lt;/strong&gt; 这三位数字代表 Intel SKU 型号划分，一般来说 Core i7 有固定几个 SKU，比方说 700；Core i5 有 600/500/400；Core i3 有 300/100 等等，一般来说数字越大说明隶属的 Core 系列越高级，同级别下比较，数字越大频率越高，换句话说性能就越强，比方说 Core i5-8600 默认 3.1GHz，睿频 4.3GHz，比 Core i5-8500 默认 3.0GHz，睿频 4.1GHz 要强。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;K&lt;/strong&gt; 带 K 的表示不锁频，可以配合 Z 系列主板进行超频操作，适合会超频玩家使用，比方说 i7-12700K，i5-12600K 等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;F&lt;/strong&gt; 带 F 的表示不带集成显卡，&lt;strong&gt;你必须配合独立显卡使用&lt;/strong&gt;；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，除了例子中的这种情况，我们还会遇到其它 CPU 型号的后缀：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;K&lt;/strong&gt;：表示支持超频且内置核显的 CPU 型号，例如型号：i5-12600K、i7-12700K；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;F&lt;/strong&gt;：表示无内置核显，例如型号：i5-12400F、i7-12700F；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KF&lt;/strong&gt;：表示支持超频且无内置核显的 CPU 型号，例如型号：i5-12600KF，i7-12700KF。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;T&lt;/strong&gt;：表示低功耗版，相同型号下功耗更低，性能也差一些，例如型号：i7-10700T；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X/XE&lt;/strong&gt;：表示至尊旗舰级，例如型号：i9-10980XE。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KS&lt;/strong&gt;：可以理解为官方超频版，提升了主频的版本，例如 i9-9900K 和 i9-9900KS，i9-9900KS 出厂的主频要高于 K，例如型号：i9-9900KS。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;U&lt;/strong&gt;：低电压，性能弱些但功耗低，通常出现在轻薄本中，举例型号：i7 10510U；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;H&lt;/strong&gt;：标压，性能强，通常出现在游戏本中，举例型号：i5-11300H&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Y&lt;/strong&gt;：超低电压，性能很弱功耗非常低，通常出现在轻薄本中，举例型号：i3-10110Y；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HK&lt;/strong&gt;：一般使用在 Intel 高端发烧级 CPU 上，可超频，举例型号：i9-11980HK；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G&lt;/strong&gt;：G1、G4 以及 G7 等，G 后面的数字表示核显性能强弱，数字越大代表核显性能越强，通常数字小于 4 的是集成的普通超高清 (UHD) 核显，大于等于 4 的是集成的高性能锐炬 (Iris) 核显。Intel 移动版 CPU 后缀，举例型号：i5-1155G7、i3-1115G4、i3-1005G1；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HQ&lt;/strong&gt;：标准电压，Q 板载四核，早期的老后缀，举例型号：i7-7700HQ；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MQ&lt;/strong&gt;：标准电压，Q 插拔四核，早期的老后缀，举例型号：i7-4810MQ；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;M&lt;/strong&gt;：早期后缀 M 就是移动端 CPU，只是为了与台式机区别开，举例型号：i7-2620M。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;主板&#34;&gt;主板&lt;/h3&gt;
&lt;h4 id=&#34;atxmicro-atxmini-itx-区别&#34;&gt;ATX，Micro-ATX，Mini-ITX 区别&lt;/h4&gt;
&lt;p&gt;在了解买啥主板时，不免会看到各种 TX，比如我买的这块七彩虹 B460iTX 主板，简称就是七彩虹 B460i，还有不带最后字母&lt;code&gt;i&lt;/code&gt;的。他们有啥区别呢？其实这就是表示了主板的尺寸。主板尺寸常见的有三种尺寸：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;标准-ATX：30.5 厘米 x 24.4 厘米&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Micro-ATX：24.4 cm x 24.4 cm&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mini-ITX：17 厘米 x 17 厘米&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/17-03-20-6cc06a3d6fbf9247c002ff2aacbb89bd-20220910170319-1e2047.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/17-03-20-6cc06a3d6fbf9247c002ff2aacbb89bd-20220910170319-1e2047.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;一般攒机会用标准 ATX，或者 MATX 也很常用，而 ITX 就常被用来搭建低功耗的服务器，如我们要搭建的 NAS。因为它是 7*24 小时不间断工作的，功耗是需要多考虑的。&lt;/p&gt;
&lt;h3 id=&#34;散热器&#34;&gt;散热器&lt;/h3&gt;
&lt;h4 id=&#34;风冷与水冷&#34;&gt;风冷与水冷&lt;/h4&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-02-33-f393351f39da51508625fc8283335b1c-20220911100231-f4fd24.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-02-33-f393351f39da51508625fc8283335b1c-20220911100231-f4fd24.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;风冷就是散热鳍片加风扇。散热鳍片会穿入铜管，铜管与下方底座相连，底座与 CPU 直接接触。CPU 热量铜管底座传导给铜管，铜管传导给散热鳍片，散热鳍片铜管风扇散热。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-04-38-a5cb1d964c6f3dd6fc71c2bca88d4369-20220911100437-034a9d.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-04-38-a5cb1d964c6f3dd6fc71c2bca88d4369-20220911100437-034a9d.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;水冷就是水冷头加风扇。简单理解就是风冷的铜管换成了液体。液体流动传导比铜管更快。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-05-10-47f4e854323ea9e8d86896342153705a-20220911100509-80682d.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-05-10-47f4e854323ea9e8d86896342153705a-20220911100509-80682d.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;各有优缺点，风冷更安全，比较简单，性能上限比较低，而水冷在外观、性能方面有很大的优势，缺点就是相对比较贵，还有漏液风险，不过现在的水冷漏液概率很小。细分的话风冷还有下压式，下压式比较适合 itx 小机箱，而塔式就适合普通机箱，水冷也分一体式水冷和分体式水冷，常见的都是一体式水冷。&lt;/p&gt;
&lt;h3 id=&#34;机箱&#34;&gt;机箱&lt;/h3&gt;
&lt;h4 id=&#34;塔式机架与刀片区别&#34;&gt;塔式，机架与刀片区别&lt;/h4&gt;
&lt;p&gt;塔式服务器外形和普通家用服务器相差不多，塔式主机在主板扩展上有优势，一般预留接口较多，方便扩展。适用于入门和工作站。&lt;/p&gt;
&lt;p&gt;机架服务器的外观安装工业标准统一设计，需要配合机柜统一使用，主要用于企业服务器密集部署。机架服务器因为需要密集紧凑，所以在设计时会非常紧凑，充分利用有限的空间。机架服务器宽度 19 英寸，高度以 U 为单位 (1U=1.75 英寸 =44.45 毫米）.&lt;/p&gt;
&lt;p&gt;刀片服务器的主体结构是主体机箱中可以有许多热拔插的主板，每一块主板都可以独立运行自己的系统，这些主板可以集合成一个服务器集群，在集群模式下可以连接起来提供更好的网络以及共享资源。&lt;/p&gt;
&lt;h4 id=&#34;全塔中塔与小塔区别&#34;&gt;全塔，中塔与小塔区别&lt;/h4&gt;
&lt;p&gt;形容的是机箱的大小。&lt;/p&gt;
&lt;p&gt;普通机箱，只能放 mATX 主板和一个标准电源，仅有 1-2 个光驱位；&lt;/p&gt;
&lt;p&gt;中塔机箱 AT，X 主板甚至是 EATX 主板和一个标准电源，拥有 3-4 个光驱位；&lt;/p&gt;
&lt;p&gt;全塔机箱，可以在主板上下的位置都安放一个电源，一共放两个电源拥有 4 个以上的光驱位。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-48-02-b90a4e4404769b82bc4d601d082bdf72-20220910224802-d6b6f5.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-48-02-b90a4e4404769b82bc4d601d082bdf72-20220910224802-d6b6f5.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;内存&#34;&gt;内存&lt;/h3&gt;
&lt;h3 id=&#34;电源&#34;&gt;电源&lt;/h3&gt;
&lt;h4 id=&#34;全模组半模组与非模组区别&#34;&gt;全模组，半模组与非模组区别&lt;/h4&gt;
&lt;p&gt;总结一句话就是能不能拔掉不需要的供电线，能拔多少。&lt;/p&gt;
&lt;h5 id=&#34;非模组&#34;&gt;非模组&lt;/h5&gt;
&lt;p&gt;一个都不能拔，电源线直接从电源内部引出，输出线缆固定，无法进行扩展。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-23-12-6d2af37077c958056be73653cfffd322-20220910222311-675160.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-23-12-6d2af37077c958056be73653cfffd322-20220910222311-675160.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h5 id=&#34;半模组&#34;&gt;半模组&lt;/h5&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-32-37-16daab986b991e007eeff650353e0479-20220910223236-f0ab87.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-32-37-16daab986b991e007eeff650353e0479-20220910223236-f0ab87.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;能拔一部分，输出设计上既有非模组电源的直出线，又有全模组电源的扩展接口。&lt;/p&gt;
&lt;h5 id=&#34;全模组&#34;&gt;全模组&lt;/h5&gt;
&lt;p&gt;能全拔，所有线缆都能按需插上。因为一般一块主板不会把所有电源线都用上，这样只需要插上自己需要的线缆即可，可以保证走线清楚，机箱清爽。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-20-52-266a816bdbffa27b7d2ad02eabb07a52-20220910222051-61c37f.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-20-52-266a816bdbffa27b7d2ad02eabb07a52-20220910222051-61c37f.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h4 id=&#34;金牌银牌和铜牌啥区别&#34;&gt;金牌，银牌和铜牌啥区别&lt;/h4&gt;
&lt;p&gt;金牌，银牌，铜牌指的是电源的转换效率。有钛金、白金、金牌、银牌、铜牌、白牌等档次，档次越高，转换效率也越高，但成本也越高，功率越小，相对成本也越高。每个“牌”对应的攻略转换或者参数也是不同的。&lt;/p&gt;
&lt;p&gt;白牌：最低要求是 20-100% 负载下，转换效率必须达到 80%；&lt;/p&gt;
&lt;p&gt;铜牌：与上同条件大于等于 82%，85%@50% 负载；&lt;/p&gt;
&lt;p&gt;银牌：大于等于 85%，88%@50% 负载；&lt;/p&gt;
&lt;p&gt;金牌：大于等于 87%，90%@50% 负载；&lt;/p&gt;
&lt;p&gt;白金牌：90%@20% 负载、92%@50% 负载、89%@100% 负载。&lt;/p&gt;
&lt;p&gt;钛金牌：要求 10%、20%、50%、100% 负载下的效率分别为 90%、94%、96%、92%。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;举个例子：
500w 金牌和 500w 铜牌，都能带动 500w 功耗的电脑。金牌电源在 100% 负载时，转换率超过 87%，可以算一下，500/0.87=575w 耗电。
铜牌 100% 负载转换率超过 82% 500/0.82=610w耗电，简单说就是好电源省电。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;硬盘&#34;&gt;硬盘&lt;/h3&gt;
&lt;h4 id=&#34;固态硬盘&#34;&gt;固态硬盘&lt;/h4&gt;
&lt;h4 id=&#34;机械硬盘&#34;&gt;机械硬盘&lt;/h4&gt;
&lt;h5 id=&#34;垂直盘-pmr-与叠瓦盘-smr-区别&#34;&gt;垂直盘 PMR 与叠瓦盘 SMR 区别&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;作者：一起学点什么
链接：&lt;a href=&#34;https://www.zhihu.com/question/369882964/answer/2227127605&#34;&gt;https://www.zhihu.com/question/369882964/answer/2227127605&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;垂直磁记录（Perpendicular magnetic recording，PMR），也称为传统磁性记录 (conventional magnetic recording，CMR)，由于 SMR 其实也是垂直式磁记录的一种，只是相较于垂直磁记录方式磁盘优化了写入密度，因此为了避免被认为所有垂直磁记录的硬盘都是 SMR 硬盘，大家也习惯把非 SMR 的垂直机械盘称为 CMR。&lt;/p&gt;
&lt;p&gt;最开始由于硬盘容量提升的需求，磁性记录颗粒的尺寸需要不断下降，导致出现了电磁学上的超顺磁效应（超顺磁性：当某些具有磁性的颗粒小于某个尺寸时，外场产生的磁取向力太小而无法抵抗热扰动的干扰，而导致其磁化性质与顺磁体（通俗来说就是指材料对磁场响应很弱的磁）相似。），这就限制了硬盘容量提升的潜力。&lt;/p&gt;
&lt;p&gt;之前硬盘厂商使用纵向（平行，Longitudinal Magnetic Recording，LMR）读写技术，磁性记录颗粒的易磁化方向相对于碟片是平行的，颗粒沿着碟片圆周以端对端排列，所以便有机会出现 SS（南）和 NN（北）的互斥排列。当颗粒的尺寸不断下降而密度不断提升，在室温的情况下颗粒便会对随机的热运动异常敏感，失去稳定性，导致出现比特（0 和 1）翻转的现象，记录的数据因此被破坏。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-37-25-bcc8863e8c481995128e5057ef677657-v2-0c0c8d0fa144f9492a3f4599bcff3fa2_720w-d47981.jpeg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-37-25-bcc8863e8c481995128e5057ef677657-v2-0c0c8d0fa144f9492a3f4599bcff3fa2_720w-d47981.jpeg&#34; alt=&#34;平行读写方式和垂直读写方式&#34;  title=&#34;
平行读写方式和垂直读写方式&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;而为了解决以上问题，后来就开发出了垂直磁记录技术（Perpendicular Recording）的硬盘，这种硬盘中的磁性记录颗粒的易磁化方向相对于碟片是垂直的，允许使用单极磁头配合磁记录介质下的软磁层将信息写入磁记录介质中，这样采用具有相同饱和磁化强度的材料所制备的垂直写入磁头，能产生远多于传统写入磁头所能产生的磁场。更大的写入磁场允许我们使用具有更高磁各向异性的材料来制备磁记录介质，而磁各向异性越强，出现超顺磁性效应的临界体积就越小，因此，碟片中的存储密度可以在一定程度内得到进一步的提高。&lt;/p&gt;
&lt;p&gt;但是这样虽然提高了硬盘的存储密度，但是很快也就达到了瓶颈，工程师又开始想新的方法来提高硬盘的存储密度，这就诞生了大家都知道的 SMR 叠瓦盘。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-37-44-9854e0b7be55864a3c8d88d85706ae3e-v2-70621980e9aa04789beee8ac77360de4_720w-bdb6ea.jpeg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-37-44-9854e0b7be55864a3c8d88d85706ae3e-v2-70621980e9aa04789beee8ac77360de4_720w-bdb6ea.jpeg&#34; alt=&#34;传统垂直读写硬盘的写入磁头和读写磁头的宽度&#34;  title=&#34;传统垂直读写硬盘的写入磁头和读写磁头的宽度&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;叠瓦式机械硬盘（Shingled magnetic recording，SMR，直译为分层磁记录）：也是一种用于硬盘驱动器的磁存储数据记录技术，可提高存储密度和每个驱动器的整体存储容量。常规的硬盘驱动器通过写入彼此平行而不重叠的磁道来记录数据，例如 PMR。而叠瓦磁记录技术的硬盘写入的新磁道则与先前写入的磁道部分重叠，从而使先前的磁道更窄，因此能拥有更高的磁道密度，进而提高磁盘容量。使用叠瓦磁技术的磁道相互重叠，与用作屋顶的瓦片堆叠方式类似。之所以能这样做是因为磁盘写入磁头由于物理上的原因比读取磁头宽上许多，因而由正常方式写入的磁道宽度远比读取磁头所需的磁道宽度来得宽，此外为了避免磁道间相互干扰，磁道和磁道之间其实还有一部分空隙，因此读取信息的磁道仅占所有磁道的很小一部分，很大的磁盘空间都被浪费了，只是因为技术原因我们不能将写入磁头制作的和读取磁头一样小。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-38-47-933fcaeee57c194da4f9583cf2298ab8-v2-d64bf87cc1454f8ec91a398abfbbedc6_720w-d978c7.jpeg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-38-47-933fcaeee57c194da4f9583cf2298ab8-v2-d64bf87cc1454f8ec91a398abfbbedc6_720w-d978c7.jpeg&#34; alt=&#34;CMR 硬盘原理&#34;  title=&#34;CMR硬盘原理&#34; style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-38-58-83f62c2d4e2e8cbcdec45f6befd1be96-v2-6f1171496af614dea6c148afe5953a43_720w-c5eb05.jpeg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-38-58-83f62c2d4e2e8cbcdec45f6befd1be96-v2-6f1171496af614dea6c148afe5953a43_720w-c5eb05.jpeg&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;由于磁道存在重叠，叠瓦式磁盘的写入过程较为复杂。如果我们随机写入一个磁道，由于写入磁头的宽度比磁道宽，因此写入会影响到临近磁道，如果这个临近磁道有数据，这些数据就也需要依次重写以免数据被破坏，依此类推。因此，SMR 磁盘一般分成很多块只能追加数据（顺序写入）的区域（Zone），这和固态硬盘的闪存页管理类似。使用“设备管理”（device-managed）方式的 SMR 磁盘通过内部固件处理了 SMR 磁盘复杂的写入问题，从而对用户封装了 SMR 磁盘的复杂性，令用户可以像使用 PMR 硬盘一样随机写入 SMR 硬盘。其他 SMR 磁盘则使用“主机管理”（host-managed）方式，需要操作系统识别 SMR 磁盘并拥有能对 SMR 磁盘进行正确顺序写入的驱动程序才能被正常使用。&lt;/p&gt;
&lt;p&gt;叠瓦盘相较于垂直盘性能也有一定下降，因为传统的 CMR 硬盘磁道之间不会互相干扰，写入数据时可以任意进行写入，而叠瓦盘由于在一个磁道写入数据时不可避免会影响相邻的磁道，需要将下一磁道的数据先拿出（暂时放入硬盘 CMR 缓冲区）再进行写入，而恢复下一磁道的数据则又会对下下磁道的数据进行影响，则又需要先取出下下磁道的数据，因此完成传统垂直硬盘一次的写入操作，叠瓦式硬盘则需要多次的写入，同样的数据量需要更多的写入操作，也会增大损坏的概率。&lt;/p&gt;
&lt;h2 id=&#34;配件选购&#34;&gt;配件选购&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;配件&lt;/th&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;型号&lt;/th&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;价格&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;主板&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;七彩虹 B460-ITX&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;300^1^&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;CPU&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;I3-10100&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;600^1^&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;机箱&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;Invasion X5&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;330^1^&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;电源&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;振华冰山金蝶 550W&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;300^1^&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;硬盘&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;西数 HC550&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;1390&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;SSD&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;xxxxx&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;旧电脑拆的&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;散热器&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;利民 AX120 RSE&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;74&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;内存条&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;酷兽 DDR4 16G&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;245&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;&lt;strong&gt;合计&lt;/strong&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;&lt;strong&gt;3239&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;1.表示二手价格&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;主板-1&#34;&gt;主板&lt;/h3&gt;
&lt;p&gt;刚入门其实最头疼的就是到底买什么型号，因为各个配件之间又有兼容问题，比如相中了一款 ITX 的机箱，但是主板却是 ATX 的，主板都放不进机箱里，这就很麻烦。所以我们首先要确定一个配件，其余配件都安装这个配件的规格去买，并且都要适配这个配件。那么这个配件最好的选择就是主板。&lt;/p&gt;
&lt;p&gt;我们先确定自己要买一个什么样的主板，让所有其他的配件都适配这个主板。选择主板的好处是，主板上各个接口就能体现出这台 NAS 的性能。不至于配件买的太离谱。&lt;/p&gt;
&lt;h3 id=&#34;机箱-1&#34;&gt;机箱&lt;/h3&gt;
&lt;p&gt;微型机箱买 ITX 板，MINI 机箱买 M-ATX 板和 ITX 板，中塔机箱买 ATX 板。因为 NAS 是个服务器，可能会永远被放在墙角，所以颜值不重要，实用才是王道，买一个盘位多实用性强的就行。&lt;/p&gt;
&lt;p&gt;在前期准备时看到很多推荐迎广的机箱，本来决定要买它，但是了解到 NAS 的本质就是一台电脑主机时，意识到为何不买个电脑机箱？为何要选择成品的机箱？虽然成品的 NAS 机箱有硬盘位，可热插拔。但是我为啥要去插拔服务器上的硬盘？&lt;/p&gt;
&lt;p&gt;当我有这个意识后，我的选择一下子多了起来，我最终选了逛淘宝偶然看的 Invasion 机箱。十分简约的外形，甚至还有玻璃侧罩，四格金属硬盘架专为 NAS 打造。只要不到三百块。于是立马转头打开小黄鱼，一搜还真有转卖的，升级版的 8 格硬盘架只要 330。收到货后也很满意，几乎是全新的，玻璃膜都没有撕，还送了俩风扇。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/4d93dc601559f515fbe2a0e261eb2776.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/4d93dc601559f515fbe2a0e261eb2776.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/0264f7b051cac66705feee6e3441dd52.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/0264f7b051cac66705feee6e3441dd52.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;cpu-1&#34;&gt;CPU&lt;/h3&gt;
&lt;p&gt;选择 CPU 对于小白来说最重要的就是要选择带核显的 CPU，因为 NAS 上显卡其实没必要，CPU 的核显就绰绰有余了，如果既没有显卡也没有核显就会无法亮机。所以选择 CPU 时要选择带核显的，也就是 Intel 的 CPU 型号不带&lt;code&gt;F&lt;/code&gt;的，比如我最终选择的 I3-10100。AMD 的 CPU 型号标识我也没弄清楚，可以自己搜索一下自己想要的 CPU 是否有核显。&lt;/p&gt;
&lt;p&gt;其次就是功耗，因为 NAS 要 7*24 小时运行，所以选择性能低一点的 CPU 就好了，另外就是需要关注 CPU 是否有音视频解码的能力。因为平时爱折腾，想着以后指不定在 NAS 上折腾些啥，所以选择了性能不算低的 I3-10100。两个月体验下来，性能还是过剩了，日常基本上都处于待机状态，只有周末看电影会用一下，CPU 利用率很低，好在日常功耗只有 30W。-&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/6e6ec183f0c08fc29eb6b01410090dce.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/6e6ec183f0c08fc29eb6b01410090dce.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;安装-ovm-openmediavaultt&#34;&gt;安装 OVM (OpenMediaVaultt)&lt;/h2&gt;
&lt;p&gt;参考视频：&lt;a href=&#34;https://www.bilibili.com/video/BV1FJ411s7xR?spm_id_from=333.999.0.0&amp;amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44&#34;&gt;蜗牛星际安装开源 NAS 系统 Openmediavault 及初始化配置（司波图）——OMV 系列教程 01&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;为什么选择它&#34;&gt;为什么选择它&lt;/h3&gt;
&lt;p&gt;OpenMediaVault（以下均简称 OMV）是除 FreeNAS 外目前使用最广泛的开源 NAS 系统。&lt;/p&gt;
&lt;h3 id=&#34;预备软件下载&#34;&gt;预备软件下载&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://www.openmediavault.org/download.html&#34;&gt;下载 OpenMediaVaultt 系统&lt;/a&gt;，我选择的是 ISO 格式 Old Stable 版本，虽然想用最新的版本，但是第一次安装没有成功，选择了旧版本安装成功了。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.wepe.com.cn/&#34;&gt;下载 微 PE 工具箱&lt;/a&gt;，用来格式化系统盘，如果是新买的系统盘就不需要下载。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://rufus.ie/zh/&#34;&gt;下载 Rufus 轻松创建 USB 启动盘&lt;/a&gt;，这个必须要用的。&lt;/p&gt;
&lt;h3 id=&#34;制作启动盘&#34;&gt;制作启动盘&lt;/h3&gt;
&lt;p&gt;需要一个容量大于 4G 的 U 盘，用 Rufus 将 OMV 写入 U 盘即可。安装时会从 U 盘启动，然后将系统安装到插在主板上的系统盘内。&lt;/p&gt;
&lt;p&gt;启动盘制作就不详细说了，都是一键式操作。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/14-36-53-d083a346dc428783efefcddcb2a46001-20220911143652-19d632.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/14-36-53-d083a346dc428783efefcddcb2a46001-20220911143652-19d632.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;制作完后进入 U 盘内查看是否写入成功&lt;/strong&gt;，U 盘内是否有文件，或者查看一下 U 盘使用大小，如果比系统 ISO 大小还小，那肯定没有写成功。我就制作了三遍才发现没有写成功，虽然能看到启动选项，但是进入安装就黑屏，因为根本没有可以安装的文件。&lt;/p&gt;
&lt;p&gt;如果没有制作成功，尝试&lt;strong&gt;格式化&lt;/strong&gt;U 盘后重新制作。&lt;/p&gt;
&lt;h3 id=&#34;安装过程&#34;&gt;安装过程&lt;/h3&gt;
&lt;p&gt;参考视频即可，很详细。&lt;/p&gt;
&lt;h3 id=&#34;踩坑记录&#34;&gt;踩坑记录&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# python&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# vim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install vim
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;docker-配置&#34;&gt;Docker 配置&lt;/h2&gt;
&lt;h3 id=&#34;安装-portainer-管理容器&#34;&gt;安装 Portainer 管理容器&lt;/h3&gt;
&lt;h3 id=&#34;更换国内镜像源&#34;&gt;更换国内镜像源&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/18-55-03-a846141c4a3997752a278ef1c604c554-20220910185502-99a3e2.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/18-55-03-a846141c4a3997752a278ef1c604c554-20220910185502-99a3e2.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/18-58-15-eefc8207a6905d28a7b76e0a142f18d5-20220910185815-3b0c01.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/18-58-15-eefc8207a6905d28a7b76e0a142f18d5-20220910185815-3b0c01.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网易 &lt;code&gt;http://hub-mirror.c.163.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ustc &lt;code&gt;http://docker.mirrors.ustc.edu.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;阿里云 &lt;code&gt;http://&amp;lt;你的 ID&amp;gt;.mirror.aliyuncs.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;或者使用一位网友提供的    &lt;code&gt;http://1nj0zren.mirror.aliyuncs.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为可能有朋友看了比较老的教程（比如我，:( ），可能会用到一些停止服务的进行，如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://dockerhub.azk8s.cn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://reg-mirror.qiniu.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://registry.docker-cn.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果无法拉取镜像，检查是否用了这几个，如果用了请换镜像源。&lt;/p&gt;
&lt;h3 id=&#34;安装-jellyfin-部署影音服务器&#34;&gt;安装 Jellyfin 部署影音服务器&lt;/h3&gt;
&lt;h3 id=&#34;安装-transmission-下载&#34;&gt;安装 Transmission 下载&lt;/h3&gt;
&lt;h3 id=&#34;安装-qbittorrent-下载&#34;&gt;安装 qBittorrent 下载&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/16-06-33-65041d0b29059db114c6bd10b20ab2f2-20220911160632-a3bdd5.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/16-06-33-65041d0b29059db114c6bd10b20ab2f2-20220911160632-a3bdd5.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/16-07-40-0ace26a48fbe6b421fdc1ad168d752f9-20220911160739-66337b.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/16-07-40-0ace26a48fbe6b421fdc1ad168d752f9-20220911160739-66337b.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h4 id=&#34;添加-tracker-list&#34;&gt;添加 tracker list&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/ngosang/trackerslist&#34;&gt;ngosang/trackerslist: Updated list of public BitTorrent trackers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/19-58-26-68faa5378bc8e252b13251e864575545-20220910195825-1f3492.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/19-58-26-68faa5378bc8e252b13251e864575545-20220910195825-1f3492.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;安装-jackett-搜索种子&#34;&gt;安装 Jackett 搜索种子&lt;/h3&gt;
&lt;p&gt;Docker 中安装，选择网易的镜像，阿里的镜像太旧了。&lt;/p&gt;
&lt;p&gt;配置端口号&lt;code&gt;9117&lt;/code&gt;，映射两个路径即可。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/15-24-34-0d1575f2892b0426b6885e28d550337e-20220911152433-8a2a1d.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/15-24-34-0d1575f2892b0426b6885e28d550337e-20220911152433-8a2a1d.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/15-27-11-008863a6cee878d735268752cf4b7ffa-20220911152710-5366dc.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/15-27-11-008863a6cee878d735268752cf4b7ffa-20220911152710-5366dc.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;安装过程参考&lt;a href=&#34;https://github.com/qbittorrent/search-plugins/wiki/How-to-configure-Jackett-plugin&#34;&gt;How to configure Jackett plugin&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;点击&lt;a href=&#34;https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/jackett.py&#34;&gt;这里下载源码&lt;/a&gt;，复制全文并保存为&lt;code&gt;jackett.py&lt;/code&gt;文件。&lt;/p&gt;
&lt;p&gt;如果按照以上安装 qBittorrent 那么保存路径为共享文件夹下&lt;code&gt;appdata/qBittorrent/nova3/engines/&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果没找到，找找是否有以下路径。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;~/.local/share/data/qBittorrent/nova3/engines/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 或者&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;~/.local/share/qBittorrent/nova3/engines/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再在相同路径下，新建一个配置文件&lt;code&gt;jackett.json&lt;/code&gt;，写入以下配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;api_key&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;YOUR_API_KEY_HERE&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;tracker_first&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 如果你登录 OMV 的地址是 192.168.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http://192.168.0.1:9117&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;安装-hlink-硬链接持续做种&#34;&gt;安装 Hlink 硬链接持续做种&lt;/h3&gt;
&lt;p&gt;下载的文件名太过杂乱，可以用 TMM 等刮削工具刮削，重命名，建立影音库。但是重命名后就无法做种。想起了 Linux 有硬链接功能，在&lt;a href=&#34;https://dunky-z.github.io/2021/08/03/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ln%E8%BD%AF%E7%A1%AC%E9%93%BE%E6%8E%A5/&#34;&gt;每天学命令-ln 软硬链接&lt;/a&gt;这篇文章中有详细说明。简言之就是创建的硬链接可以任意&lt;strong&gt;修改文件名&lt;/strong&gt;，看上去是一份拷贝，但是&lt;strong&gt;实际不占用硬盘空间&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;下载的文件太多，又是文件夹嵌套，手动创建比较麻烦，有人专门为这个需求开源了一个项目&lt;a href=&#34;https://hlink.likun.me/&#34;&gt;hlink&lt;/a&gt;，可以批量创建硬链接。这里还是以使用 Docker 为例。&lt;/p&gt;
&lt;h4 id=&#34;配置-docker&#34;&gt;配置 Docker&lt;/h4&gt;
&lt;p&gt;镜像名：likun7981/hlink
端口号：9090
目录映射：/media :  /root/sharedfolder
环境变量：HLINK_HOME：/root/sharedfolder/appdata/hlink  选择自己放配置文件的目录即可&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;/root/sharedfolder 是我挂载的硬盘的根目录，建议映射根目录，不要创建多个目录，比如映射/root/sharedfolder/movie 和/root/sharedfolder/music。因为硬链接不支持跨盘符创建，虽然我们本地 music 和 movie 是在一个盘符，但是这样&lt;strong&gt;映射在容器中就是两个盘&lt;/strong&gt;，就会无法创建硬链接，所以只映射一个根目录。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/10-23-24-4ece9b26e4043a836b1fa2a2781600b9-20220912102324-27d38f.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/10-23-24-4ece9b26e4043a836b1fa2a2781600b9-20220912102324-27d38f.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/09-41-48-1cd8143da0c9ffaca54a212f2ffd670e-20220912094147-3cc75f.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/09-41-48-1cd8143da0c9ffaca54a212f2ffd670e-20220912094147-3cc75f.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/09-41-15-50e436e132411b5528505e58911d636b-20220912094115-081991.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/09-41-15-50e436e132411b5528505e58911d636b-20220912094115-081991.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h4 id=&#34;配置-hlink&#34;&gt;配置 Hlink&lt;/h4&gt;
&lt;p&gt;浏览器输入 IP:9090，打开配置界面。&lt;/p&gt;
&lt;p&gt;添加一个新配置，注释十分详细，就不赘述了，但是路径一定要写对，可以新建两个测试目录，测试一下是否能够创建成功。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/10-32-40-510edbcdcf05ffe8054b5581ed7c9057-20220912103239-8b23ae.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/10-32-40-510edbcdcf05ffe8054b5581ed7c9057-20220912103239-8b23ae.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;两个重要配置解释：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;/media&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;是容器里的目录，因为我只映射了一个目录，所以这就是容器的根目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;对应到我主机，就是/root/sharedfolder&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;这个目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;所以/media/downloads/qbittorrent/qbcomplete/movie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;就是/root/sharedfolder/downloads/qbittorrent/qbcomplete/movie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;后一个路径/media/media/movie&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;同理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;等价于/root/sharedfolder/media/movie&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;err&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;err&#34;&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;前一个路径是下载的路径，这里的文件都是不能重命名整理的&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;后一个路径是影音库的路径，hlink&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;执行完会在这里创建相同的文件链接&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;这个链接可以任意修改，移动，删除&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;pathsMapping:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;err&#34;&gt;&amp;#39;/media/downloads/qbittorrent/qbcomplete/movie&amp;#39;:&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;&amp;#39;/media/media/movie&amp;#39;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;/**&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;设置&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;打开缓存，这样即使影音库里的文件被删除，移动&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;err&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;也不会创建新的硬链接&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;err&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;openCache:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;缓存的文件信息在右上角&lt;strong&gt;编辑缓存&lt;/strong&gt;可以查看，如果已经执行过创建硬链接但是没有显示，&lt;code&gt;Shfit+F5&lt;/code&gt;刷新界面重试。&lt;/p&gt;
&lt;h2 id=&#34;踩坑记录-1&#34;&gt;踩坑记录&lt;/h2&gt;
&lt;h3 id=&#34;主板无法识别固态硬盘&#34;&gt;主板无法识别固态硬盘&lt;/h3&gt;
&lt;p&gt;因为想利用上三年前从笔记本上拆下来的固态，但没注意接口的协议。主板现在大多默认支持 NEVe 协议，但是我的硬盘是很久之前的 SATA 协议。这块 B460i 主板默认支持 NVMe 协议的，但是也支持 SATA 协议，需要更改跳帽。&lt;/p&gt;
&lt;p&gt;找了半天图片没有找到一样的，官网的图片是和说明书上的一样是拨动开关形式的，但是我买的二手的是跳帽（哭），不会是买到假的了吧。开关全部拨到左边才支持 SATA 协议。用跳帽也是一样，必须都连接的是左边两个引脚。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/16-11-07-355ce9f2442639e47b0e24f9773b2e84-20220910161106-f6986f.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/16-11-07-355ce9f2442639e47b0e24f9773b2e84-20220910161106-f6986f.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/16-09-53-5ceae123a355652ef1f45bb0e9b72dd9-20220910160952-9c6773.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/16-09-53-5ceae123a355652ef1f45bb0e9b72dd9-20220910160952-9c6773.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;无法识别-u-盘启动盘&#34;&gt;无法识别 U 盘启动盘&lt;/h3&gt;
&lt;p&gt;引导模式有两种 UEFI 和 Legacy，这个在做启动盘时就确定了。如果主板使用的 UEFI 模式，而启动盘制作的是 Legacy 模式，就无法识别，需要在 Bios 里找到启动模式选择的相关选项，配置可以使用 Legacy 模式或者 UEFI。（记录这些时已经不想再进 Bios 了所以也没有图片，总之要配置引导方式，避免过滤了一些引导方式导致 U 盘无法识别）&lt;/p&gt;
&lt;h3 id=&#34;不同网段设备无法互通&#34;&gt;不同网段设备无法互通&lt;/h3&gt;
&lt;h3 id=&#34;ovm-无法挂载移动硬盘&#34;&gt;OVM 无法挂载移动硬盘&lt;/h3&gt;
&lt;p&gt;报错：The filesystem label contains blanks. Please remove them by renaming the filesystem to be able to mount it.&lt;/p&gt;
&lt;p&gt;移动硬盘名里有空格，插到 Windows 上重命名一下即可。&lt;/p&gt;
&lt;h3 id=&#34;ifconfig-not-found&#34;&gt;ifconfig not found&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# ifconfig&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install net-tools
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ll-not-found&#34;&gt;ll not found&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 找到 #alias ll=’ls -l’，去掉前面的#就可以了。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/498113584&#34;&gt;CPU 型号解读：教你 CPU 型号后缀怎么看？CPU 型号后面的字母和数字区别是什么？ - 知乎&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://einverne.github.io/post/2018/12/build-nas-from-scratch.html&#34;&gt;从零开始搭建 NAS: 硬件篇 | Verne in GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://einverne.github.io/post/2020/02/build-nas-from-scratch-software.html&#34;&gt;从零搭建一台 NAS：软件篇 | Verne in GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.csdn.net/mahoon411/article/details/106963398&#34;&gt;Intel CPU 型号解读以及如何粗略判断 Intel CPU 的性能 (i3、i5、i7 以及 CPU 的代数)_吮指原味张的博客-CSDN 博客_cpu 代数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.zuiyu1818.cn/posts/NAS_qBittorrent.html&#34;&gt;NAS | 群晖安装 qBittorrent 套件并优化设置、替换 UI（非 docker 安装） | 醉渔小站&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.jianshu.com/p/405fe33b9032&#34;&gt;Docker 中国源 - 简书&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.antec.com.cn/index.php?m=content&amp;amp;c=index&amp;amp;a=show&amp;amp;catid=41&amp;amp;id=57&#34;&gt;金牌 铜牌 什么区别呀？ - 电源 - Antec 网站&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.tspweb.com/key/%E9%93%9C%E7%89%8C%E7%94%B5%E6%BA%90%E5%92%8C%E9%87%91%E7%89%8C%E7%94%B5%E6%BA%90%E7%9A%84%E5%8C%BA%E5%88%AB.html&#34;&gt;机·科普贴：电脑电源金、银、铜牌到底是什么意思？_铜牌电源和金牌电源的区别 - 调色盘网络&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/50797978&#34;&gt;【非模组电源，半模组电源，全模组电源有什么区别？】 - 知乎&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://post.smzdm.com/p/awx49n72/&#34;&gt;电源全模组和非模组究竟有什么区别？_电脑电源_什么值得买&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zhuanlan.zhihu.com/p/25592446&#34;&gt;浅谈组装机机箱的选择（篇一：大小） - 知乎&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://howthere.org/zh-hant/%E5%93%AA%E7%A8%AE-pc-%E6%A9%9F%E7%AE%B1%E5%B0%BA%E5%AF%B8%E6%9C%80%E9%81%A9%E5%90%88%E6%82%A8%E7%9A%84%E4%B8%8B%E4%B8%80%E5%80%8B%E7%89%88%E6%9C%AC%EF%BC%9F&#34;&gt;哪種 PC 機箱尺寸最適合您的下一個版本？ - HowThere&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.expreview.com/49306-all.html&#34;&gt;199 元风冷/水冷散热器简单对比：谁才是你的爱 - 超能网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.bilibili.com/video/BV1FJ411s7xR?spm_id_from=333.999.0.0&amp;amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44&#34;&gt;【教程】蜗牛星际安装开源 NAS 系统 Openmediavault 及初始化配置（司波图）——OMV 系列教程 01_哔哩哔哩_bilibili&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/qbittorrent/search-plugins/wiki/How-to-configure-Jackett-plugin&#34;&gt;How to configure Jackett plugin · qbittorrent/search-plugins Wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.bilibili.com/video/BV1aa411R7hn?spm_id_from=333.337.search-card.all.click&amp;amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44&#34;&gt;安装 NAS Tools，打造自动化观影、追剧系统，NAS 媒体库整理工具，威联通 Docker 版 NAS Tools 安装教程~feat.威联通 HS 264_哔哩哔哩_bilibili&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hlink.likun.me/&#34;&gt;Home | hlink&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
      <content:encoded><![CDATA[<p>技术没学多少，教程下满了硬盘，一直想专门部署 NAS 来存文件，但是一来要花钱，二来搭建 NAS 没有经验怕部署不好，没有现在硬盘直连舒适，所以将就用吧。</p>
<p>自从有天忘了忘了休眠电脑，一个自动备份任务开启，在 40 度的高温天，满速跑了一天，下班回来硬盘直接报废。这就加速我折腾部署 NAS 的进程。</p>
<h2 id="准备阶段">准备阶段</h2>
<p>威联通的几款中意的 NAS 放购物车很久了，如果硬盘没有这么早坏掉，可能在双十一就买整机了，现在离双十一还早，硬件价格都不便宜，想来想去还是买二手硬件攒一台更划算。如果买整机，硬盘加 NAS 主机就得五千大洋，只是用来存文件，部署个 Jellyfin 看电影用，属实奢侈了。</p>
<p>￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥￥</p>
<p>买二手就得从零开始学。生命不休，折腾不止。经过一次完整的 NAS 攒机过程发现，其实 NAS 就是安装了专用系统的一台电脑而已。这个专用系统就是面向网络存储开发的，如群晖，威联通，开源的 OMV，FreeNAS 等等。</p>
<p>既然是一台电脑，其实攒 NAS 就和攒电脑一样，选配好以下几大件即可。</p>
<ul>
<li>CPU</li>
<li>主板</li>
<li>散热器</li>
<li>机箱</li>
<li>内存</li>
<li>电源</li>
<li>机箱风扇</li>
</ul>
<p>下面分别介绍在攒机过程中遇到的一些概念，参数到底是什么意思。</p>
<h3 id="cpu">CPU</h3>
<h4 id="cpu-型号字母数字都是什么意思">CPU 型号字母数字都是什么意思</h4>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/19-03-26-07978c9e6aae76e3d1a4ac48df0521f1-20220910190326-c46d16.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/19-03-26-07978c9e6aae76e3d1a4ac48df0521f1-20220910190326-c46d16.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<ul>
<li><strong>Intel</strong> 是英特尔的英文名称，也是目前热门的 CPU 品牌；</li>
<li>“酷睿”代表英特尔品牌下面向普通消费者的一个 CPU 系列，一般划分为 Core（酷睿）、Pentium（奔腾）、Celeron（赛扬）、Xeon（至强）、Atom（凌动）等；</li>
<li><strong>i5</strong> 代表这款 CPU 定位中端，在其下面还有 i3，在其上面还有 i7 和 i9，同一代中，数字越大，性能越强；但是不同代 - 数之间，性能不能直接相比，比如 12 代的 i5 在理论性能上是强于 10 代 i7 的。</li>
<li><strong>12</strong> 代表这款 CPU 的代数，说明其已经发展到第十二代了，数字越大越新；</li>
<li><strong>600</strong> 这三位数字代表 Intel SKU 型号划分，一般来说 Core i7 有固定几个 SKU，比方说 700；Core i5 有 600/500/400；Core i3 有 300/100 等等，一般来说数字越大说明隶属的 Core 系列越高级，同级别下比较，数字越大频率越高，换句话说性能就越强，比方说 Core i5-8600 默认 3.1GHz，睿频 4.3GHz，比 Core i5-8500 默认 3.0GHz，睿频 4.1GHz 要强。</li>
<li><strong>K</strong> 带 K 的表示不锁频，可以配合 Z 系列主板进行超频操作，适合会超频玩家使用，比方说 i7-12700K，i5-12600K 等</li>
<li><strong>F</strong> 带 F 的表示不带集成显卡，<strong>你必须配合独立显卡使用</strong>；</li>
</ul>
<p>当然，除了例子中的这种情况，我们还会遇到其它 CPU 型号的后缀：</p>
<ul>
<li><strong>K</strong>：表示支持超频且内置核显的 CPU 型号，例如型号：i5-12600K、i7-12700K；</li>
<li><strong>F</strong>：表示无内置核显，例如型号：i5-12400F、i7-12700F；</li>
<li><strong>KF</strong>：表示支持超频且无内置核显的 CPU 型号，例如型号：i5-12600KF，i7-12700KF。</li>
<li><strong>T</strong>：表示低功耗版，相同型号下功耗更低，性能也差一些，例如型号：i7-10700T；</li>
<li><strong>X/XE</strong>：表示至尊旗舰级，例如型号：i9-10980XE。</li>
<li><strong>KS</strong>：可以理解为官方超频版，提升了主频的版本，例如 i9-9900K 和 i9-9900KS，i9-9900KS 出厂的主频要高于 K，例如型号：i9-9900KS。</li>
<li><strong>U</strong>：低电压，性能弱些但功耗低，通常出现在轻薄本中，举例型号：i7 10510U；</li>
<li><strong>H</strong>：标压，性能强，通常出现在游戏本中，举例型号：i5-11300H</li>
<li><strong>Y</strong>：超低电压，性能很弱功耗非常低，通常出现在轻薄本中，举例型号：i3-10110Y；</li>
<li><strong>HK</strong>：一般使用在 Intel 高端发烧级 CPU 上，可超频，举例型号：i9-11980HK；</li>
<li><strong>G</strong>：G1、G4 以及 G7 等，G 后面的数字表示核显性能强弱，数字越大代表核显性能越强，通常数字小于 4 的是集成的普通超高清 (UHD) 核显，大于等于 4 的是集成的高性能锐炬 (Iris) 核显。Intel 移动版 CPU 后缀，举例型号：i5-1155G7、i3-1115G4、i3-1005G1；</li>
<li><strong>HQ</strong>：标准电压，Q 板载四核，早期的老后缀，举例型号：i7-7700HQ；</li>
<li><strong>MQ</strong>：标准电压，Q 插拔四核，早期的老后缀，举例型号：i7-4810MQ；</li>
<li><strong>M</strong>：早期后缀 M 就是移动端 CPU，只是为了与台式机区别开，举例型号：i7-2620M。</li>
</ul>
<h3 id="主板">主板</h3>
<h4 id="atxmicro-atxmini-itx-区别">ATX，Micro-ATX，Mini-ITX 区别</h4>
<p>在了解买啥主板时，不免会看到各种 TX，比如我买的这块七彩虹 B460iTX 主板，简称就是七彩虹 B460i，还有不带最后字母<code>i</code>的。他们有啥区别呢？其实这就是表示了主板的尺寸。主板尺寸常见的有三种尺寸：</p>
<ul>
<li>
<p>标准-ATX：30.5 厘米 x 24.4 厘米</p>
</li>
<li>
<p>Micro-ATX：24.4 cm x 24.4 cm</p>
</li>
<li>
<p>Mini-ITX：17 厘米 x 17 厘米</p>
</li>
</ul>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/17-03-20-6cc06a3d6fbf9247c002ff2aacbb89bd-20220910170319-1e2047.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/17-03-20-6cc06a3d6fbf9247c002ff2aacbb89bd-20220910170319-1e2047.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>一般攒机会用标准 ATX，或者 MATX 也很常用，而 ITX 就常被用来搭建低功耗的服务器，如我们要搭建的 NAS。因为它是 7*24 小时不间断工作的，功耗是需要多考虑的。</p>
<h3 id="散热器">散热器</h3>
<h4 id="风冷与水冷">风冷与水冷</h4>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-02-33-f393351f39da51508625fc8283335b1c-20220911100231-f4fd24.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-02-33-f393351f39da51508625fc8283335b1c-20220911100231-f4fd24.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>风冷就是散热鳍片加风扇。散热鳍片会穿入铜管，铜管与下方底座相连，底座与 CPU 直接接触。CPU 热量铜管底座传导给铜管，铜管传导给散热鳍片，散热鳍片铜管风扇散热。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-04-38-a5cb1d964c6f3dd6fc71c2bca88d4369-20220911100437-034a9d.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-04-38-a5cb1d964c6f3dd6fc71c2bca88d4369-20220911100437-034a9d.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>水冷就是水冷头加风扇。简单理解就是风冷的铜管换成了液体。液体流动传导比铜管更快。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-05-10-47f4e854323ea9e8d86896342153705a-20220911100509-80682d.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-05-10-47f4e854323ea9e8d86896342153705a-20220911100509-80682d.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>各有优缺点，风冷更安全，比较简单，性能上限比较低，而水冷在外观、性能方面有很大的优势，缺点就是相对比较贵，还有漏液风险，不过现在的水冷漏液概率很小。细分的话风冷还有下压式，下压式比较适合 itx 小机箱，而塔式就适合普通机箱，水冷也分一体式水冷和分体式水冷，常见的都是一体式水冷。</p>
<h3 id="机箱">机箱</h3>
<h4 id="塔式机架与刀片区别">塔式，机架与刀片区别</h4>
<p>塔式服务器外形和普通家用服务器相差不多，塔式主机在主板扩展上有优势，一般预留接口较多，方便扩展。适用于入门和工作站。</p>
<p>机架服务器的外观安装工业标准统一设计，需要配合机柜统一使用，主要用于企业服务器密集部署。机架服务器因为需要密集紧凑，所以在设计时会非常紧凑，充分利用有限的空间。机架服务器宽度 19 英寸，高度以 U 为单位 (1U=1.75 英寸 =44.45 毫米）.</p>
<p>刀片服务器的主体结构是主体机箱中可以有许多热拔插的主板，每一块主板都可以独立运行自己的系统，这些主板可以集合成一个服务器集群，在集群模式下可以连接起来提供更好的网络以及共享资源。</p>
<h4 id="全塔中塔与小塔区别">全塔，中塔与小塔区别</h4>
<p>形容的是机箱的大小。</p>
<p>普通机箱，只能放 mATX 主板和一个标准电源，仅有 1-2 个光驱位；</p>
<p>中塔机箱 AT，X 主板甚至是 EATX 主板和一个标准电源，拥有 3-4 个光驱位；</p>
<p>全塔机箱，可以在主板上下的位置都安放一个电源，一共放两个电源拥有 4 个以上的光驱位。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-48-02-b90a4e4404769b82bc4d601d082bdf72-20220910224802-d6b6f5.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-48-02-b90a4e4404769b82bc4d601d082bdf72-20220910224802-d6b6f5.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="内存">内存</h3>
<h3 id="电源">电源</h3>
<h4 id="全模组半模组与非模组区别">全模组，半模组与非模组区别</h4>
<p>总结一句话就是能不能拔掉不需要的供电线，能拔多少。</p>
<h5 id="非模组">非模组</h5>
<p>一个都不能拔，电源线直接从电源内部引出，输出线缆固定，无法进行扩展。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-23-12-6d2af37077c958056be73653cfffd322-20220910222311-675160.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-23-12-6d2af37077c958056be73653cfffd322-20220910222311-675160.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h5 id="半模组">半模组</h5>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-32-37-16daab986b991e007eeff650353e0479-20220910223236-f0ab87.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-32-37-16daab986b991e007eeff650353e0479-20220910223236-f0ab87.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>能拔一部分，输出设计上既有非模组电源的直出线，又有全模组电源的扩展接口。</p>
<h5 id="全模组">全模组</h5>
<p>能全拔，所有线缆都能按需插上。因为一般一块主板不会把所有电源线都用上，这样只需要插上自己需要的线缆即可，可以保证走线清楚，机箱清爽。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-20-52-266a816bdbffa27b7d2ad02eabb07a52-20220910222051-61c37f.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/22-20-52-266a816bdbffa27b7d2ad02eabb07a52-20220910222051-61c37f.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h4 id="金牌银牌和铜牌啥区别">金牌，银牌和铜牌啥区别</h4>
<p>金牌，银牌，铜牌指的是电源的转换效率。有钛金、白金、金牌、银牌、铜牌、白牌等档次，档次越高，转换效率也越高，但成本也越高，功率越小，相对成本也越高。每个“牌”对应的攻略转换或者参数也是不同的。</p>
<p>白牌：最低要求是 20-100% 负载下，转换效率必须达到 80%；</p>
<p>铜牌：与上同条件大于等于 82%，85%@50% 负载；</p>
<p>银牌：大于等于 85%，88%@50% 负载；</p>
<p>金牌：大于等于 87%，90%@50% 负载；</p>
<p>白金牌：90%@20% 负载、92%@50% 负载、89%@100% 负载。</p>
<p>钛金牌：要求 10%、20%、50%、100% 负载下的效率分别为 90%、94%、96%、92%。</p>
<blockquote>
<p>举个例子：
500w 金牌和 500w 铜牌，都能带动 500w 功耗的电脑。金牌电源在 100% 负载时，转换率超过 87%，可以算一下，500/0.87=575w 耗电。
铜牌 100% 负载转换率超过 82% 500/0.82=610w耗电，简单说就是好电源省电。</p>
</blockquote>
<h3 id="硬盘">硬盘</h3>
<h4 id="固态硬盘">固态硬盘</h4>
<h4 id="机械硬盘">机械硬盘</h4>
<h5 id="垂直盘-pmr-与叠瓦盘-smr-区别">垂直盘 PMR 与叠瓦盘 SMR 区别</h5>
<blockquote>
<p>作者：一起学点什么
链接：<a href="https://www.zhihu.com/question/369882964/answer/2227127605">https://www.zhihu.com/question/369882964/answer/2227127605</a></p>
</blockquote>
<p>垂直磁记录（Perpendicular magnetic recording，PMR），也称为传统磁性记录 (conventional magnetic recording，CMR)，由于 SMR 其实也是垂直式磁记录的一种，只是相较于垂直磁记录方式磁盘优化了写入密度，因此为了避免被认为所有垂直磁记录的硬盘都是 SMR 硬盘，大家也习惯把非 SMR 的垂直机械盘称为 CMR。</p>
<p>最开始由于硬盘容量提升的需求，磁性记录颗粒的尺寸需要不断下降，导致出现了电磁学上的超顺磁效应（超顺磁性：当某些具有磁性的颗粒小于某个尺寸时，外场产生的磁取向力太小而无法抵抗热扰动的干扰，而导致其磁化性质与顺磁体（通俗来说就是指材料对磁场响应很弱的磁）相似。），这就限制了硬盘容量提升的潜力。</p>
<p>之前硬盘厂商使用纵向（平行，Longitudinal Magnetic Recording，LMR）读写技术，磁性记录颗粒的易磁化方向相对于碟片是平行的，颗粒沿着碟片圆周以端对端排列，所以便有机会出现 SS（南）和 NN（北）的互斥排列。当颗粒的尺寸不断下降而密度不断提升，在室温的情况下颗粒便会对随机的热运动异常敏感，失去稳定性，导致出现比特（0 和 1）翻转的现象，记录的数据因此被破坏。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-37-25-bcc8863e8c481995128e5057ef677657-v2-0c0c8d0fa144f9492a3f4599bcff3fa2_720w-d47981.jpeg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-37-25-bcc8863e8c481995128e5057ef677657-v2-0c0c8d0fa144f9492a3f4599bcff3fa2_720w-d47981.jpeg" alt="平行读写方式和垂直读写方式"  title="
平行读写方式和垂直读写方式" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>而为了解决以上问题，后来就开发出了垂直磁记录技术（Perpendicular Recording）的硬盘，这种硬盘中的磁性记录颗粒的易磁化方向相对于碟片是垂直的，允许使用单极磁头配合磁记录介质下的软磁层将信息写入磁记录介质中，这样采用具有相同饱和磁化强度的材料所制备的垂直写入磁头，能产生远多于传统写入磁头所能产生的磁场。更大的写入磁场允许我们使用具有更高磁各向异性的材料来制备磁记录介质，而磁各向异性越强，出现超顺磁性效应的临界体积就越小，因此，碟片中的存储密度可以在一定程度内得到进一步的提高。</p>
<p>但是这样虽然提高了硬盘的存储密度，但是很快也就达到了瓶颈，工程师又开始想新的方法来提高硬盘的存储密度，这就诞生了大家都知道的 SMR 叠瓦盘。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-37-44-9854e0b7be55864a3c8d88d85706ae3e-v2-70621980e9aa04789beee8ac77360de4_720w-bdb6ea.jpeg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-37-44-9854e0b7be55864a3c8d88d85706ae3e-v2-70621980e9aa04789beee8ac77360de4_720w-bdb6ea.jpeg" alt="传统垂直读写硬盘的写入磁头和读写磁头的宽度"  title="传统垂直读写硬盘的写入磁头和读写磁头的宽度" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>叠瓦式机械硬盘（Shingled magnetic recording，SMR，直译为分层磁记录）：也是一种用于硬盘驱动器的磁存储数据记录技术，可提高存储密度和每个驱动器的整体存储容量。常规的硬盘驱动器通过写入彼此平行而不重叠的磁道来记录数据，例如 PMR。而叠瓦磁记录技术的硬盘写入的新磁道则与先前写入的磁道部分重叠，从而使先前的磁道更窄，因此能拥有更高的磁道密度，进而提高磁盘容量。使用叠瓦磁技术的磁道相互重叠，与用作屋顶的瓦片堆叠方式类似。之所以能这样做是因为磁盘写入磁头由于物理上的原因比读取磁头宽上许多，因而由正常方式写入的磁道宽度远比读取磁头所需的磁道宽度来得宽，此外为了避免磁道间相互干扰，磁道和磁道之间其实还有一部分空隙，因此读取信息的磁道仅占所有磁道的很小一部分，很大的磁盘空间都被浪费了，只是因为技术原因我们不能将写入磁头制作的和读取磁头一样小。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-38-47-933fcaeee57c194da4f9583cf2298ab8-v2-d64bf87cc1454f8ec91a398abfbbedc6_720w-d978c7.jpeg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-38-47-933fcaeee57c194da4f9583cf2298ab8-v2-d64bf87cc1454f8ec91a398abfbbedc6_720w-d978c7.jpeg" alt="CMR 硬盘原理"  title="CMR硬盘原理" style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-38-58-83f62c2d4e2e8cbcdec45f6befd1be96-v2-6f1171496af614dea6c148afe5953a43_720w-c5eb05.jpeg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/10-38-58-83f62c2d4e2e8cbcdec45f6befd1be96-v2-6f1171496af614dea6c148afe5953a43_720w-c5eb05.jpeg" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>由于磁道存在重叠，叠瓦式磁盘的写入过程较为复杂。如果我们随机写入一个磁道，由于写入磁头的宽度比磁道宽，因此写入会影响到临近磁道，如果这个临近磁道有数据，这些数据就也需要依次重写以免数据被破坏，依此类推。因此，SMR 磁盘一般分成很多块只能追加数据（顺序写入）的区域（Zone），这和固态硬盘的闪存页管理类似。使用“设备管理”（device-managed）方式的 SMR 磁盘通过内部固件处理了 SMR 磁盘复杂的写入问题，从而对用户封装了 SMR 磁盘的复杂性，令用户可以像使用 PMR 硬盘一样随机写入 SMR 硬盘。其他 SMR 磁盘则使用“主机管理”（host-managed）方式，需要操作系统识别 SMR 磁盘并拥有能对 SMR 磁盘进行正确顺序写入的驱动程序才能被正常使用。</p>
<p>叠瓦盘相较于垂直盘性能也有一定下降，因为传统的 CMR 硬盘磁道之间不会互相干扰，写入数据时可以任意进行写入，而叠瓦盘由于在一个磁道写入数据时不可避免会影响相邻的磁道，需要将下一磁道的数据先拿出（暂时放入硬盘 CMR 缓冲区）再进行写入，而恢复下一磁道的数据则又会对下下磁道的数据进行影响，则又需要先取出下下磁道的数据，因此完成传统垂直硬盘一次的写入操作，叠瓦式硬盘则需要多次的写入，同样的数据量需要更多的写入操作，也会增大损坏的概率。</p>
<h2 id="配件选购">配件选购</h2>
<table>
	<thead>
			<tr>
					<th style="text-align: center">配件</th>
					<th style="text-align: center">型号</th>
					<th style="text-align: center">价格</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: center">主板</td>
					<td style="text-align: center">七彩虹 B460-ITX</td>
					<td style="text-align: center">300^1^</td>
			</tr>
			<tr>
					<td style="text-align: center">CPU</td>
					<td style="text-align: center">I3-10100</td>
					<td style="text-align: center">600^1^</td>
			</tr>
			<tr>
					<td style="text-align: center">机箱</td>
					<td style="text-align: center">Invasion X5</td>
					<td style="text-align: center">330^1^</td>
			</tr>
			<tr>
					<td style="text-align: center">电源</td>
					<td style="text-align: center">振华冰山金蝶 550W</td>
					<td style="text-align: center">300^1^</td>
			</tr>
			<tr>
					<td style="text-align: center">硬盘</td>
					<td style="text-align: center">西数 HC550</td>
					<td style="text-align: center">1390</td>
			</tr>
			<tr>
					<td style="text-align: center">SSD</td>
					<td style="text-align: center">xxxxx</td>
					<td style="text-align: center">旧电脑拆的</td>
			</tr>
			<tr>
					<td style="text-align: center">散热器</td>
					<td style="text-align: center">利民 AX120 RSE</td>
					<td style="text-align: center">74</td>
			</tr>
			<tr>
					<td style="text-align: center">内存条</td>
					<td style="text-align: center">酷兽 DDR4 16G</td>
					<td style="text-align: center">245</td>
			</tr>
			<tr>
					<td style="text-align: center"><strong>合计</strong></td>
					<td style="text-align: center"></td>
					<td style="text-align: center"><strong>3239</strong></td>
			</tr>
	</tbody>
</table>
<blockquote>
<p>1.表示二手价格</p>
</blockquote>
<h3 id="主板-1">主板</h3>
<p>刚入门其实最头疼的就是到底买什么型号，因为各个配件之间又有兼容问题，比如相中了一款 ITX 的机箱，但是主板却是 ATX 的，主板都放不进机箱里，这就很麻烦。所以我们首先要确定一个配件，其余配件都安装这个配件的规格去买，并且都要适配这个配件。那么这个配件最好的选择就是主板。</p>
<p>我们先确定自己要买一个什么样的主板，让所有其他的配件都适配这个主板。选择主板的好处是，主板上各个接口就能体现出这台 NAS 的性能。不至于配件买的太离谱。</p>
<h3 id="机箱-1">机箱</h3>
<p>微型机箱买 ITX 板，MINI 机箱买 M-ATX 板和 ITX 板，中塔机箱买 ATX 板。因为 NAS 是个服务器，可能会永远被放在墙角，所以颜值不重要，实用才是王道，买一个盘位多实用性强的就行。</p>
<p>在前期准备时看到很多推荐迎广的机箱，本来决定要买它，但是了解到 NAS 的本质就是一台电脑主机时，意识到为何不买个电脑机箱？为何要选择成品的机箱？虽然成品的 NAS 机箱有硬盘位，可热插拔。但是我为啥要去插拔服务器上的硬盘？</p>
<p>当我有这个意识后，我的选择一下子多了起来，我最终选了逛淘宝偶然看的 Invasion 机箱。十分简约的外形，甚至还有玻璃侧罩，四格金属硬盘架专为 NAS 打造。只要不到三百块。于是立马转头打开小黄鱼，一搜还真有转卖的，升级版的 8 格硬盘架只要 330。收到货后也很满意，几乎是全新的，玻璃膜都没有撕，还送了俩风扇。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/4d93dc601559f515fbe2a0e261eb2776.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/4d93dc601559f515fbe2a0e261eb2776.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/0264f7b051cac66705feee6e3441dd52.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/0264f7b051cac66705feee6e3441dd52.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="cpu-1">CPU</h3>
<p>选择 CPU 对于小白来说最重要的就是要选择带核显的 CPU，因为 NAS 上显卡其实没必要，CPU 的核显就绰绰有余了，如果既没有显卡也没有核显就会无法亮机。所以选择 CPU 时要选择带核显的，也就是 Intel 的 CPU 型号不带<code>F</code>的，比如我最终选择的 I3-10100。AMD 的 CPU 型号标识我也没弄清楚，可以自己搜索一下自己想要的 CPU 是否有核显。</p>
<p>其次就是功耗，因为 NAS 要 7*24 小时运行，所以选择性能低一点的 CPU 就好了，另外就是需要关注 CPU 是否有音视频解码的能力。因为平时爱折腾，想着以后指不定在 NAS 上折腾些啥，所以选择了性能不算低的 I3-10100。两个月体验下来，性能还是过剩了，日常基本上都处于待机状态，只有周末看电影会用一下，CPU 利用率很低，好在日常功耗只有 30W。-</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/6e6ec183f0c08fc29eb6b01410090dce.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/10/22/6e6ec183f0c08fc29eb6b01410090dce.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="安装-ovm-openmediavaultt">安装 OVM (OpenMediaVaultt)</h2>
<p>参考视频：<a href="https://www.bilibili.com/video/BV1FJ411s7xR?spm_id_from=333.999.0.0&amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44">蜗牛星际安装开源 NAS 系统 Openmediavault 及初始化配置（司波图）——OMV 系列教程 01</a></p>
<h3 id="为什么选择它">为什么选择它</h3>
<p>OpenMediaVault（以下均简称 OMV）是除 FreeNAS 外目前使用最广泛的开源 NAS 系统。</p>
<h3 id="预备软件下载">预备软件下载</h3>
<p><a href="https://www.openmediavault.org/download.html">下载 OpenMediaVaultt 系统</a>，我选择的是 ISO 格式 Old Stable 版本，虽然想用最新的版本，但是第一次安装没有成功，选择了旧版本安装成功了。</p>
<p><a href="https://www.wepe.com.cn/">下载 微 PE 工具箱</a>，用来格式化系统盘，如果是新买的系统盘就不需要下载。</p>
<p><a href="https://rufus.ie/zh/">下载 Rufus 轻松创建 USB 启动盘</a>，这个必须要用的。</p>
<h3 id="制作启动盘">制作启动盘</h3>
<p>需要一个容量大于 4G 的 U 盘，用 Rufus 将 OMV 写入 U 盘即可。安装时会从 U 盘启动，然后将系统安装到插在主板上的系统盘内。</p>
<p>启动盘制作就不详细说了，都是一键式操作。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/14-36-53-d083a346dc428783efefcddcb2a46001-20220911143652-19d632.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/14-36-53-d083a346dc428783efefcddcb2a46001-20220911143652-19d632.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p><strong>制作完后进入 U 盘内查看是否写入成功</strong>，U 盘内是否有文件，或者查看一下 U 盘使用大小，如果比系统 ISO 大小还小，那肯定没有写成功。我就制作了三遍才发现没有写成功，虽然能看到启动选项，但是进入安装就黑屏，因为根本没有可以安装的文件。</p>
<p>如果没有制作成功，尝试<strong>格式化</strong>U 盘后重新制作。</p>
<h3 id="安装过程">安装过程</h3>
<p>参考视频即可，很详细。</p>
<h3 id="踩坑记录">踩坑记录</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># git</span>
</span></span><span class="line"><span class="cl">sudo apt install git
</span></span><span class="line"><span class="cl"><span class="c1"># python</span>
</span></span><span class="line"><span class="cl">sudo apt install python
</span></span><span class="line"><span class="cl"><span class="c1"># vim</span>
</span></span><span class="line"><span class="cl">sudo apt install vim
</span></span></code></pre></div><h2 id="docker-配置">Docker 配置</h2>
<h3 id="安装-portainer-管理容器">安装 Portainer 管理容器</h3>
<h3 id="更换国内镜像源">更换国内镜像源</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/18-55-03-a846141c4a3997752a278ef1c604c554-20220910185502-99a3e2.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/18-55-03-a846141c4a3997752a278ef1c604c554-20220910185502-99a3e2.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/18-58-15-eefc8207a6905d28a7b76e0a142f18d5-20220910185815-3b0c01.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/18-58-15-eefc8207a6905d28a7b76e0a142f18d5-20220910185815-3b0c01.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<ul>
<li>网易 <code>http://hub-mirror.c.163.com</code></li>
<li>ustc <code>http://docker.mirrors.ustc.edu.cn</code></li>
<li>阿里云 <code>http://&lt;你的 ID&gt;.mirror.aliyuncs.com</code></li>
<li>或者使用一位网友提供的    <code>http://1nj0zren.mirror.aliyuncs.com</code></li>
</ul>
<p>因为可能有朋友看了比较老的教程（比如我，:( ），可能会用到一些停止服务的进行，如：</p>
<ul>
<li><code>https://dockerhub.azk8s.cn</code></li>
<li><code>https://reg-mirror.qiniu.com</code></li>
<li><code>https://registry.docker-cn.com</code></li>
</ul>
<p>如果无法拉取镜像，检查是否用了这几个，如果用了请换镜像源。</p>
<h3 id="安装-jellyfin-部署影音服务器">安装 Jellyfin 部署影音服务器</h3>
<h3 id="安装-transmission-下载">安装 Transmission 下载</h3>
<h3 id="安装-qbittorrent-下载">安装 qBittorrent 下载</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/16-06-33-65041d0b29059db114c6bd10b20ab2f2-20220911160632-a3bdd5.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/16-06-33-65041d0b29059db114c6bd10b20ab2f2-20220911160632-a3bdd5.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/16-07-40-0ace26a48fbe6b421fdc1ad168d752f9-20220911160739-66337b.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/16-07-40-0ace26a48fbe6b421fdc1ad168d752f9-20220911160739-66337b.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h4 id="添加-tracker-list">添加 tracker list</h4>
<p><a href="https://github.com/ngosang/trackerslist">ngosang/trackerslist: Updated list of public BitTorrent trackers</a></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/19-58-26-68faa5378bc8e252b13251e864575545-20220910195825-1f3492.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/19-58-26-68faa5378bc8e252b13251e864575545-20220910195825-1f3492.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="安装-jackett-搜索种子">安装 Jackett 搜索种子</h3>
<p>Docker 中安装，选择网易的镜像，阿里的镜像太旧了。</p>
<p>配置端口号<code>9117</code>，映射两个路径即可。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/15-24-34-0d1575f2892b0426b6885e28d550337e-20220911152433-8a2a1d.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/15-24-34-0d1575f2892b0426b6885e28d550337e-20220911152433-8a2a1d.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/15-27-11-008863a6cee878d735268752cf4b7ffa-20220911152710-5366dc.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/15-27-11-008863a6cee878d735268752cf4b7ffa-20220911152710-5366dc.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>安装过程参考<a href="https://github.com/qbittorrent/search-plugins/wiki/How-to-configure-Jackett-plugin">How to configure Jackett plugin</a>。</p>
<p>点击<a href="https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/jackett.py">这里下载源码</a>，复制全文并保存为<code>jackett.py</code>文件。</p>
<p>如果按照以上安装 qBittorrent 那么保存路径为共享文件夹下<code>appdata/qBittorrent/nova3/engines/</code>。</p>
<p>如果没找到，找找是否有以下路径。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">~/.local/share/data/qBittorrent/nova3/engines/
</span></span><span class="line"><span class="cl"><span class="c1"># 或者</span>
</span></span><span class="line"><span class="cl">~/.local/share/qBittorrent/nova3/engines/
</span></span></code></pre></div><p>再在相同路径下，新建一个配置文件<code>jackett.json</code>，写入以下配置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;api_key&#34;</span><span class="p">:</span> <span class="s2">&#34;YOUR_API_KEY_HERE&#34;</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;tracker_first&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">    <span class="c1">// 如果你登录 OMV 的地址是 192.168.0.1
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;url&#34;</span><span class="p">:</span> <span class="s2">&#34;http://192.168.0.1:9117&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="安装-hlink-硬链接持续做种">安装 Hlink 硬链接持续做种</h3>
<p>下载的文件名太过杂乱，可以用 TMM 等刮削工具刮削，重命名，建立影音库。但是重命名后就无法做种。想起了 Linux 有硬链接功能，在<a href="https://dunky-z.github.io/2021/08/03/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ln%E8%BD%AF%E7%A1%AC%E9%93%BE%E6%8E%A5/">每天学命令-ln 软硬链接</a>这篇文章中有详细说明。简言之就是创建的硬链接可以任意<strong>修改文件名</strong>，看上去是一份拷贝，但是<strong>实际不占用硬盘空间</strong>。</p>
<p>下载的文件太多，又是文件夹嵌套，手动创建比较麻烦，有人专门为这个需求开源了一个项目<a href="https://hlink.likun.me/">hlink</a>，可以批量创建硬链接。这里还是以使用 Docker 为例。</p>
<h4 id="配置-docker">配置 Docker</h4>
<p>镜像名：likun7981/hlink
端口号：9090
目录映射：/media :  /root/sharedfolder
环境变量：HLINK_HOME：/root/sharedfolder/appdata/hlink  选择自己放配置文件的目录即可</p>
<blockquote>
<p>/root/sharedfolder 是我挂载的硬盘的根目录，建议映射根目录，不要创建多个目录，比如映射/root/sharedfolder/movie 和/root/sharedfolder/music。因为硬链接不支持跨盘符创建，虽然我们本地 music 和 movie 是在一个盘符，但是这样<strong>映射在容器中就是两个盘</strong>，就会无法创建硬链接，所以只映射一个根目录。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/10-23-24-4ece9b26e4043a836b1fa2a2781600b9-20220912102324-27d38f.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/10-23-24-4ece9b26e4043a836b1fa2a2781600b9-20220912102324-27d38f.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
</blockquote>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/09-41-48-1cd8143da0c9ffaca54a212f2ffd670e-20220912094147-3cc75f.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/09-41-48-1cd8143da0c9ffaca54a212f2ffd670e-20220912094147-3cc75f.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/09-41-15-50e436e132411b5528505e58911d636b-20220912094115-081991.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/09-41-15-50e436e132411b5528505e58911d636b-20220912094115-081991.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h4 id="配置-hlink">配置 Hlink</h4>
<p>浏览器输入 IP:9090，打开配置界面。</p>
<p>添加一个新配置，注释十分详细，就不赘述了，但是路径一定要写对，可以新建两个测试目录，测试一下是否能够创建成功。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/10-32-40-510edbcdcf05ffe8054b5581ed7c9057-20220912103239-8b23ae.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/12/10-32-40-510edbcdcf05ffe8054b5581ed7c9057-20220912103239-8b23ae.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>两个重要配置解释：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="err">/**</span>
</span></span><span class="line"><span class="cl"> <span class="err">*</span> <span class="err">/media</span> <span class="err">是容器里的目录，因为我只映射了一个目录，所以这就是容器的根目录</span>
</span></span><span class="line"><span class="cl"> <span class="err">*</span> <span class="err">对应到我主机，就是/root/sharedfolder</span> <span class="err">这个目录</span>
</span></span><span class="line"><span class="cl"> <span class="err">*</span> <span class="err">所以/media/downloads/qbittorrent/qbcomplete/movie</span>
</span></span><span class="line"><span class="cl"> <span class="err">*</span> <span class="err">就是/root/sharedfolder/downloads/qbittorrent/qbcomplete/movie</span>
</span></span><span class="line"><span class="cl"> <span class="err">*</span> <span class="err">后一个路径/media/media/movie</span> <span class="err">同理</span>
</span></span><span class="line"><span class="cl"> <span class="err">*</span> <span class="err">等价于/root/sharedfolder/media/movie</span>
</span></span><span class="line"><span class="cl"> <span class="err">*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="err">/**</span>
</span></span><span class="line"><span class="cl">  <span class="err">*</span> <span class="err">前一个路径是下载的路径，这里的文件都是不能重命名整理的</span>
</span></span><span class="line"><span class="cl">  <span class="err">*</span> <span class="err">后一个路径是影音库的路径，hlink</span> <span class="err">执行完会在这里创建相同的文件链接</span>
</span></span><span class="line"><span class="cl">  <span class="err">*</span> <span class="err">这个链接可以任意修改，移动，删除</span>
</span></span><span class="line"><span class="cl">  <span class="err">*/</span>
</span></span><span class="line"><span class="cl">  <span class="err">pathsMapping:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="err">&#39;/media/downloads/qbittorrent/qbcomplete/movie&#39;:</span> <span class="err">&#39;/media/media/movie&#39;,</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span><span class="err">,</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl">  <span class="err">/**</span>
</span></span><span class="line"><span class="cl">   <span class="err">*</span> <span class="err">设置</span> <span class="kc">true</span> <span class="err">打开缓存，这样即使影音库里的文件被删除，移动</span>
</span></span><span class="line"><span class="cl">   <span class="err">*</span> <span class="err">也不会创建新的硬链接</span>
</span></span><span class="line"><span class="cl">   <span class="err">*/</span>
</span></span><span class="line"><span class="cl">  <span class="err">openCache:</span> <span class="kc">true</span><span class="err">,</span>
</span></span></code></pre></div><p>缓存的文件信息在右上角<strong>编辑缓存</strong>可以查看，如果已经执行过创建硬链接但是没有显示，<code>Shfit+F5</code>刷新界面重试。</p>
<h2 id="踩坑记录-1">踩坑记录</h2>
<h3 id="主板无法识别固态硬盘">主板无法识别固态硬盘</h3>
<p>因为想利用上三年前从笔记本上拆下来的固态，但没注意接口的协议。主板现在大多默认支持 NEVe 协议，但是我的硬盘是很久之前的 SATA 协议。这块 B460i 主板默认支持 NVMe 协议的，但是也支持 SATA 协议，需要更改跳帽。</p>
<p>找了半天图片没有找到一样的，官网的图片是和说明书上的一样是拨动开关形式的，但是我买的二手的是跳帽（哭），不会是买到假的了吧。开关全部拨到左边才支持 SATA 协议。用跳帽也是一样，必须都连接的是左边两个引脚。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/16-11-07-355ce9f2442639e47b0e24f9773b2e84-20220910161106-f6986f.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/16-11-07-355ce9f2442639e47b0e24f9773b2e84-20220910161106-f6986f.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/16-09-53-5ceae123a355652ef1f45bb0e9b72dd9-20220910160952-9c6773.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/10/16-09-53-5ceae123a355652ef1f45bb0e9b72dd9-20220910160952-9c6773.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="无法识别-u-盘启动盘">无法识别 U 盘启动盘</h3>
<p>引导模式有两种 UEFI 和 Legacy，这个在做启动盘时就确定了。如果主板使用的 UEFI 模式，而启动盘制作的是 Legacy 模式，就无法识别，需要在 Bios 里找到启动模式选择的相关选项，配置可以使用 Legacy 模式或者 UEFI。（记录这些时已经不想再进 Bios 了所以也没有图片，总之要配置引导方式，避免过滤了一些引导方式导致 U 盘无法识别）</p>
<h3 id="不同网段设备无法互通">不同网段设备无法互通</h3>
<h3 id="ovm-无法挂载移动硬盘">OVM 无法挂载移动硬盘</h3>
<p>报错：The filesystem label contains blanks. Please remove them by renaming the filesystem to be able to mount it.</p>
<p>移动硬盘名里有空格，插到 Windows 上重命名一下即可。</p>
<h3 id="ifconfig-not-found">ifconfig not found</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># ifconfig</span>
</span></span><span class="line"><span class="cl">sudo apt install net-tools
</span></span></code></pre></div><h3 id="ll-not-found">ll not found</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">vim ~/.bashrc
</span></span><span class="line"><span class="cl"><span class="c1"># 找到 #alias ll=’ls -l’，去掉前面的#就可以了。</span>
</span></span><span class="line"><span class="cl"><span class="nb">source</span> ~/.bashrc
</span></span></code></pre></div><h2 id="参考">参考</h2>
<ol>
<li><a href="https://zhuanlan.zhihu.com/p/498113584">CPU 型号解读：教你 CPU 型号后缀怎么看？CPU 型号后面的字母和数字区别是什么？ - 知乎</a></li>
<li><a href="https://einverne.github.io/post/2018/12/build-nas-from-scratch.html">从零开始搭建 NAS: 硬件篇 | Verne in GitHub</a></li>
<li><a href="https://einverne.github.io/post/2020/02/build-nas-from-scratch-software.html">从零搭建一台 NAS：软件篇 | Verne in GitHub</a></li>
<li><a href="https://blog.csdn.net/mahoon411/article/details/106963398">Intel CPU 型号解读以及如何粗略判断 Intel CPU 的性能 (i3、i5、i7 以及 CPU 的代数)_吮指原味张的博客-CSDN 博客_cpu 代数</a></li>
<li><a href="https://blog.zuiyu1818.cn/posts/NAS_qBittorrent.html">NAS | 群晖安装 qBittorrent 套件并优化设置、替换 UI（非 docker 安装） | 醉渔小站</a></li>
<li><a href="https://www.jianshu.com/p/405fe33b9032">Docker 中国源 - 简书</a></li>
<li><a href="http://www.antec.com.cn/index.php?m=content&amp;c=index&amp;a=show&amp;catid=41&amp;id=57">金牌 铜牌 什么区别呀？ - 电源 - Antec 网站</a></li>
<li><a href="https://www.tspweb.com/key/%E9%93%9C%E7%89%8C%E7%94%B5%E6%BA%90%E5%92%8C%E9%87%91%E7%89%8C%E7%94%B5%E6%BA%90%E7%9A%84%E5%8C%BA%E5%88%AB.html">机·科普贴：电脑电源金、银、铜牌到底是什么意思？_铜牌电源和金牌电源的区别 - 调色盘网络</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/50797978">【非模组电源，半模组电源，全模组电源有什么区别？】 - 知乎</a></li>
<li><a href="https://post.smzdm.com/p/awx49n72/">电源全模组和非模组究竟有什么区别？_电脑电源_什么值得买</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/25592446">浅谈组装机机箱的选择（篇一：大小） - 知乎</a></li>
<li><a href="https://howthere.org/zh-hant/%E5%93%AA%E7%A8%AE-pc-%E6%A9%9F%E7%AE%B1%E5%B0%BA%E5%AF%B8%E6%9C%80%E9%81%A9%E5%90%88%E6%82%A8%E7%9A%84%E4%B8%8B%E4%B8%80%E5%80%8B%E7%89%88%E6%9C%AC%EF%BC%9F">哪種 PC 機箱尺寸最適合您的下一個版本？ - HowThere</a></li>
<li><a href="https://www.expreview.com/49306-all.html">199 元风冷/水冷散热器简单对比：谁才是你的爱 - 超能网</a></li>
<li><a href="https://www.bilibili.com/video/BV1FJ411s7xR?spm_id_from=333.999.0.0&amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44">【教程】蜗牛星际安装开源 NAS 系统 Openmediavault 及初始化配置（司波图）——OMV 系列教程 01_哔哩哔哩_bilibili</a></li>
<li><a href="https://github.com/qbittorrent/search-plugins/wiki/How-to-configure-Jackett-plugin">How to configure Jackett plugin · qbittorrent/search-plugins Wiki</a></li>
<li><a href="https://www.bilibili.com/video/BV1aa411R7hn?spm_id_from=333.337.search-card.all.click&amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44">安装 NAS Tools，打造自动化观影、追剧系统，NAS 媒体库整理工具，威联通 Docker 版 NAS Tools 安装教程~feat.威联通 HS 264_哔哩哔哩_bilibili</a></li>
<li><a href="https://hlink.likun.me/">Home | hlink</a></li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 终端回车变成^M</title>
      <link>https://lifeislife.cn/posts/linux%E7%BB%88%E7%AB%AF%E5%9B%9E%E8%BD%A6%E5%8F%98%E6%88%90-m/</link>
      <pubDate>Mon, 05 Sep 2022 15:37:58 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E7%BB%88%E7%AB%AF%E5%9B%9E%E8%BD%A6%E5%8F%98%E6%88%90-m/</guid>
      <description>&lt;h1 id=&#34;解决方法&#34;&gt;解决方法&lt;/h1&gt;
&lt;p&gt;终端执行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;stty sane
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;参考&#34;&gt;参考&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://askubuntu.com/questions/441744/pressing-enter-produces-m-instead-of-a-newline#comment578102_441744&#34;&gt;command line - Pressing enter produces ^M instead of a newline - Ask Ubuntu&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="解决方法">解决方法</h1>
<p>终端执行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">stty sane
</span></span></code></pre></div><h1 id="参考">参考</h1>
<p><a href="https://askubuntu.com/questions/441744/pressing-enter-produces-m-instead-of-a-newline#comment578102_441744">command line - Pressing enter produces ^M instead of a newline - Ask Ubuntu</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 切换不同 Python 版本</title>
      <link>https://lifeislife.cn/posts/linux%E5%88%87%E6%8D%A2%E4%B8%8D%E5%90%8Cpython%E7%89%88%E6%9C%AC/</link>
      <pubDate>Mon, 05 Sep 2022 15:31:27 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E5%88%87%E6%8D%A2%E4%B8%8D%E5%90%8Cpython%E7%89%88%E6%9C%AC/</guid>
      <description></description>
    </item>
    <item>
      <title>每天学命令-生成指定大小文件</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-%E7%94%9F%E6%88%90%E6%8C%87%E5%AE%9A%E5%A4%A7%E5%B0%8F%E6%96%87%E4%BB%B6/</link>
      <pubDate>Sat, 23 Jul 2022 16:14:38 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-%E7%94%9F%E6%88%90%E6%8C%87%E5%AE%9A%E5%A4%A7%E5%B0%8F%E6%96%87%E4%BB%B6/</guid>
      <description>&lt;h2 id=&#34;使用背景&#34;&gt;使用背景&lt;/h2&gt;
&lt;p&gt;在测试下载速度，或者测试加解密文件，亦或者制作文件系统时都需要一些指定大小的文件。Linux 有一些命令可以快速完成这样的任务。接下来介绍几个好用的命令。&lt;/p&gt;
&lt;h3 id=&#34;空洞文件&#34;&gt;空洞文件&lt;/h3&gt;
&lt;p&gt;在 Unix 文件操作中，操作文件的位移量可以大于文件的当前长度，在下一次写操作时，就会把文件撑大（Extend），在文件里创建空洞（Hole），没有被实际写入的部分都是 0。空洞文件是否占用实际磁盘空间由文件系统觉得，&lt;strong&gt;Linux 中空洞文件不占用实际磁盘空间&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;fallocate&#34;&gt;fallocate&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fallocate&lt;/code&gt;用于将块预分配给文件。对于支持&lt;code&gt;fallocate&lt;/code&gt;系统调用的文件系统，这可以通过分配块并将其标记为未初始化来快速完成，因此不需要对数据块进行 I/O 操作。这是创建文件而不是用零填充的更快的方法。大文件几乎可以立即创建，而不必等待任何 I/O 操作完成。&lt;/p&gt;
&lt;p&gt;语法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fallocate &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;-n&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;-o offset&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; -l length filename
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt;: 检测零并替换为空洞。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-n&lt;/code&gt;：指定文件的大小，单位为字节。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o&lt;/code&gt;：指定文件的偏移量，可以跟二进制$2^{N}$后缀&lt;code&gt;KiB&lt;/code&gt;，&lt;code&gt;MiB&lt;/code&gt;，&lt;code&gt;GiB&lt;/code&gt;，&lt;code&gt;TiB&lt;/code&gt;，&lt;code&gt;PiB&lt;/code&gt;和&lt;code&gt;EiB&lt;/code&gt;（&lt;code&gt;iB&lt;/code&gt;为可选，例如，&lt;code&gt;K&lt;/code&gt;的含义与&lt;code&gt;KiB&lt;/code&gt;的含义相同或后缀&lt;code&gt;KB&lt;/code&gt;，&lt;code&gt;MB&lt;/code&gt;，&lt;code&gt;GB&lt;/code&gt;，&lt;code&gt;PB&lt;/code&gt;和&lt;code&gt;EB&lt;/code&gt;的十进制（$10^{N}$）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;/code&gt;：指定文件的大小，单位同上。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p, --punch-hole&lt;/code&gt;: 将某个范围替换为空洞 (连带打开 -n)。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filename&lt;/code&gt;：指定文件名。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：
分配一个大小为&lt;code&gt;512MB&lt;/code&gt;的文件，文件名为&lt;code&gt;efi.img&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fallocate -l 512M efi.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将&lt;code&gt;efi.img&lt;/code&gt;文件中的&lt;code&gt;0&lt;/code&gt;替换为空洞：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fallocate -d efi.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从偏移 128M 的位置挖一个 10M 大小的洞&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fallocate -p -o 128M  -l 10M  efi.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;dd&#34;&gt;dd&lt;/h2&gt;
&lt;p&gt;Linux &lt;code&gt;dd&lt;/code&gt; 命令用于读取、转换并输出数据。&lt;code&gt;dd&lt;/code&gt; 可从标准输入或文件中读取数据，根据指定的格式来转换数据，再输出到文件、设备或标准输出&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;dd 的原意为 data duplicator，但由于 dd 属于较低阶的资料处理工具，通常都会以管理者（root）权限来执行，如果稍有不慎，也很容易造成严重的后果（例如整颗硬碟的资料不见等等），所以有些人也把 dd 取名为 data destroyer。&lt;a href=&#34;https://blog.gtwang.org/linux/dd-command-examples/&#34;&gt;dd 指令教学与实用范例，备份与回复资料的小工具 - GT Wang&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;if=FILE&lt;/code&gt;     : 指定输入文件，若不指定则从标注输入读取。这里指定为/dev/zero 是 Linux 的一个伪文件，它可以产生连续不断的 null 流（二进制的 0）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;of=FILE&lt;/code&gt;      : 指定输出文件，若不指定则输出到标准输出。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bs=BYTES&lt;/code&gt;     : 每次读写的字节数，可以使用单位 K、M、G 等等。另外输入输出可以分别用 ibs、obs 指定，若使用 bs，则表示是 ibs 和 obs 都是用该参数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count=BLOCKS&lt;/code&gt; : 读取的 block 数，block 的大小由 ibs 指定。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：
生成一个&lt;code&gt;1g&lt;/code&gt;大小的文件，内容全为&lt;code&gt;0&lt;/code&gt;，块大小为&lt;code&gt;1M&lt;/code&gt;，文件名为&lt;code&gt;efi.img&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dd &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&#34;nv&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;efi.img &lt;span class=&#34;nv&#34;&gt;bs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1M &lt;span class=&#34;nv&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成一个&lt;code&gt;1g&lt;/code&gt;大小的文件，内容为随机数，块大小为&lt;code&gt;10M&lt;/code&gt;，文件名为&lt;code&gt;efi.img&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dd &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/urandom &lt;span class=&#34;nv&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;efi.img &lt;span class=&#34;nv&#34;&gt;bs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;10M &lt;span class=&#34;nv&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;truncate&#34;&gt;truncate&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt;：指定文件的大小，可以跟二进制$2^{N}$后缀&lt;code&gt;KiB&lt;/code&gt;，&lt;code&gt;MiB&lt;/code&gt;，&lt;code&gt;GiB&lt;/code&gt;，&lt;code&gt;TiB&lt;/code&gt;，&lt;code&gt;PiB&lt;/code&gt;和&lt;code&gt;EiB&lt;/code&gt;（&lt;code&gt;iB&lt;/code&gt;为可选，例如，&lt;code&gt;K&lt;/code&gt;的含义与&lt;code&gt;KiB&lt;/code&gt;的含义相同或后缀&lt;code&gt;KB&lt;/code&gt;，&lt;code&gt;MB&lt;/code&gt;，&lt;code&gt;GB&lt;/code&gt;，&lt;code&gt;PB&lt;/code&gt;和&lt;code&gt;EB&lt;/code&gt;的十进制（$10^{N}$）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：
生成一个 100M 大小的文件，文件名为&lt;code&gt;efi.img&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;truncate -s 100M efi.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://lrita.github.io/images/posts/filesystem/Linux_File_Hole_And_Sparse_Files.pdf&#34;&gt;Linux 文件空洞与稀疏文件&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="使用背景">使用背景</h2>
<p>在测试下载速度，或者测试加解密文件，亦或者制作文件系统时都需要一些指定大小的文件。Linux 有一些命令可以快速完成这样的任务。接下来介绍几个好用的命令。</p>
<h3 id="空洞文件">空洞文件</h3>
<p>在 Unix 文件操作中，操作文件的位移量可以大于文件的当前长度，在下一次写操作时，就会把文件撑大（Extend），在文件里创建空洞（Hole），没有被实际写入的部分都是 0。空洞文件是否占用实际磁盘空间由文件系统觉得，<strong>Linux 中空洞文件不占用实际磁盘空间</strong>。</p>
<h2 id="fallocate">fallocate</h2>
<p><code>fallocate</code>用于将块预分配给文件。对于支持<code>fallocate</code>系统调用的文件系统，这可以通过分配块并将其标记为未初始化来快速完成，因此不需要对数据块进行 I/O 操作。这是创建文件而不是用零填充的更快的方法。大文件几乎可以立即创建，而不必等待任何 I/O 操作完成。</p>
<p>语法：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">fallocate <span class="o">[</span>-n<span class="o">]</span> <span class="o">[</span>-o offset<span class="o">]</span> -l length filename
</span></span></code></pre></div><ul>
<li><code>d</code>: 检测零并替换为空洞。</li>
<li><code>-n</code>：指定文件的大小，单位为字节。</li>
<li><code>-o</code>：指定文件的偏移量，可以跟二进制$2^{N}$后缀<code>KiB</code>，<code>MiB</code>，<code>GiB</code>，<code>TiB</code>，<code>PiB</code>和<code>EiB</code>（<code>iB</code>为可选，例如，<code>K</code>的含义与<code>KiB</code>的含义相同或后缀<code>KB</code>，<code>MB</code>，<code>GB</code>，<code>PB</code>和<code>EB</code>的十进制（$10^{N}$）。</li>
<li><code>-l</code>：指定文件的大小，单位同上。</li>
<li><code>-p, --punch-hole</code>: 将某个范围替换为空洞 (连带打开 -n)。</li>
<li><code>filename</code>：指定文件名。</li>
</ul>
<p>示例：
分配一个大小为<code>512MB</code>的文件，文件名为<code>efi.img</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">fallocate -l 512M efi.img
</span></span></code></pre></div><p>将<code>efi.img</code>文件中的<code>0</code>替换为空洞：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">fallocate -d efi.img
</span></span></code></pre></div><p>从偏移 128M 的位置挖一个 10M 大小的洞</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">fallocate -p -o 128M  -l 10M  efi.img
</span></span></code></pre></div><h2 id="dd">dd</h2>
<p>Linux <code>dd</code> 命令用于读取、转换并输出数据。<code>dd</code> 可从标准输入或文件中读取数据，根据指定的格式来转换数据，再输出到文件、设备或标准输出</p>
<blockquote>
<p>dd 的原意为 data duplicator，但由于 dd 属于较低阶的资料处理工具，通常都会以管理者（root）权限来执行，如果稍有不慎，也很容易造成严重的后果（例如整颗硬碟的资料不见等等），所以有些人也把 dd 取名为 data destroyer。<a href="https://blog.gtwang.org/linux/dd-command-examples/">dd 指令教学与实用范例，备份与回复资料的小工具 - GT Wang</a></p>
</blockquote>
<ul>
<li><code>if=FILE</code>     : 指定输入文件，若不指定则从标注输入读取。这里指定为/dev/zero 是 Linux 的一个伪文件，它可以产生连续不断的 null 流（二进制的 0）。</li>
<li><code>of=FILE</code>      : 指定输出文件，若不指定则输出到标准输出。</li>
<li><code>bs=BYTES</code>     : 每次读写的字节数，可以使用单位 K、M、G 等等。另外输入输出可以分别用 ibs、obs 指定，若使用 bs，则表示是 ibs 和 obs 都是用该参数。</li>
<li><code>count=BLOCKS</code> : 读取的 block 数，block 的大小由 ibs 指定。</li>
</ul>
<p>示例：
生成一个<code>1g</code>大小的文件，内容全为<code>0</code>，块大小为<code>1M</code>，文件名为<code>efi.img</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">dd <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span>efi.img <span class="nv">bs</span><span class="o">=</span>1M <span class="nv">count</span><span class="o">=</span><span class="m">1024</span>
</span></span></code></pre></div><p>生成一个<code>1g</code>大小的文件，内容为随机数，块大小为<code>10M</code>，文件名为<code>efi.img</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">dd <span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">of</span><span class="o">=</span>efi.img <span class="nv">bs</span><span class="o">=</span>10M <span class="nv">count</span><span class="o">=</span><span class="m">1024</span>
</span></span></code></pre></div><h2 id="truncate">truncate</h2>
<ul>
<li><code>-s</code>：指定文件的大小，可以跟二进制$2^{N}$后缀<code>KiB</code>，<code>MiB</code>，<code>GiB</code>，<code>TiB</code>，<code>PiB</code>和<code>EiB</code>（<code>iB</code>为可选，例如，<code>K</code>的含义与<code>KiB</code>的含义相同或后缀<code>KB</code>，<code>MB</code>，<code>GB</code>，<code>PB</code>和<code>EB</code>的十进制（$10^{N}$）。</li>
</ul>
<p>示例：
生成一个 100M 大小的文件，文件名为<code>efi.img</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">truncate -s 100M efi.img
</span></span></code></pre></div><h2 id="参考">参考</h2>
<p><a href="https://lrita.github.io/images/posts/filesystem/Linux_File_Hole_And_Sparse_Files.pdf">Linux 文件空洞与稀疏文件</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>理解虚拟内存</title>
      <link>https://lifeislife.cn/posts/%E7%90%86%E8%A7%A3%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98/</link>
      <pubDate>Sun, 17 Jul 2022 21:45:20 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E7%90%86%E8%A7%A3%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98/</guid>
      <description>&lt;h2 id=&#34;为什么需要虚拟内存&#34;&gt;为什么需要虚拟内存？&lt;/h2&gt;
&lt;p&gt;CPU 访问内存的最自然的方式就是使用物理地址，这种方式称为&lt;strong&gt;物理寻址&lt;/strong&gt;。1，计算机中并不是只有一个程序在运行，如果它们都是用物理寻址的方式，那么所有程序必须在链接之前确定好自己所用到的内存范围，否则两个程序就可能会发生冲突。2，程序大于内存的问题早在上世纪六十年代就出现，后来出现了&lt;strong&gt;覆盖技术&lt;/strong&gt;（Overlay），把程序分割成许多片段。程序开始执行时，将覆盖管理模块装入内存，该管理模块立即装入并运行覆盖 0。执行完成后，覆盖 0 通知管理模块装入覆盖 1，或者占用覆盖 0 的上方位置（如果有空间），或者占用覆盖 0（如果没有空间）。把一个大程序分割成小的、模块化的片段是非常费时和枯燥的，并且易于出错。很少程序员擅长使用覆盖技术。&lt;/p&gt;
&lt;p&gt;为了更加有效地管理内存并且少出错，现代系统提供了一种对主存的抽象概念，叫做&lt;strong&gt;虚拟内存&lt;/strong&gt;(VM)。主要有三个功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它将主存看成是一个存储在磁盘上的地址空间的高速缓存，在主存中只保存活动区域，并根据需要在磁盘和主存之间来回传送数据，通过这种方式，它&lt;strong&gt;高效地使用了主存&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;它为每个进程提供了一致的地址空间，从而&lt;strong&gt;简化了内存管理&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;它&lt;strong&gt;保护了每个进程&lt;/strong&gt;的地址空间不被其他进程破坏。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;什么是虚拟寻址&#34;&gt;什么是虚拟寻址？&lt;/h2&gt;
&lt;p&gt;如果主存被分为长度为$M$的单字节大小的数组，每个字节都对应一个物理地址，CPU 通过这个唯一的地址访问主存，这样的方式就是&lt;strong&gt;物理寻址&lt;/strong&gt;。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202207212125636.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202207212125636.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
现代处理器使用&lt;strong&gt;虚拟寻址&lt;/strong&gt;的方式。CPU 通过生成的&lt;strong&gt;虚拟地址&lt;/strong&gt;来访问内存，这个地址在送到内存之前会被转换成&lt;strong&gt;物理地址&lt;/strong&gt;。这个过程称为&lt;strong&gt;地址翻译&lt;/strong&gt;。CPU 芯片上叫做&lt;strong&gt;内存管理单元&lt;/strong&gt;（Memory Management Unit, MMU）的专用硬件，利用存放在主存中的&lt;strong&gt;查询表&lt;/strong&gt;来动态翻译虚拟地址，该表的内容由操作系统管理。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202207212128486.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202207212128486.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;虚拟内存作为缓存的工具&#34;&gt;虚拟内存作为缓存的工具&lt;/h2&gt;
&lt;p&gt;概念上而言，虚拟内存被组织成为一个由存放在磁盘上的 N 个连续的字节大小的单元组成的数组，也就是&lt;strong&gt;字节数组&lt;/strong&gt;。每个字节都有一个唯一的虚拟地址作为数组的索引。磁盘上活动的数组内容被缓存在主存中。在存储器结构中，较低层次上的磁盘的数据被分割成块，这些块作为和较高层次的主存之间的传输单元。&lt;strong&gt;主存作为虚拟内存的缓存&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;虚拟内存被分割为大小固定的块，这些块叫&lt;strong&gt;虚拟页&lt;/strong&gt;（Virtual Page，VP），类似的物理内存也有&lt;strong&gt;物理页&lt;/strong&gt;(Physical Page, PP)。虚拟页有三种不同的状态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;未分配：VM 系统还未分配 (或者创建）的页。未分配的块没有任何数据和它们相关联，因此也就&lt;strong&gt;不占用任何磁盘空间&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;已缓存：当前已缓存在物理内存中的已分配页。&lt;/li&gt;
&lt;li&gt;未缓存：未缓存在物理内存中的已分配页。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了有助于清晰理解存储层次结构中不同的缓存概念，我们将使用术语&lt;strong&gt;SRAM&lt;/strong&gt;缓存来表示位于 CPU 和主存之间的 Ll、L2 和 L3 &lt;strong&gt;高速缓存&lt;/strong&gt;，并且用术语 &lt;strong&gt;DRAM&lt;/strong&gt; 缓存来表示&lt;strong&gt;虚拟内存系统的缓存&lt;/strong&gt;，它在主存中缓存虚拟页。&lt;/p&gt;
&lt;p&gt;在存储层次结构中，DRAM 缓存的位置对它的组织结构有很大的影响。回想一下，DRAM 比 SRAM 要慢大约 10 倍，而磁盘要比 DRAM 慢大约 100000 多倍。因此，&lt;strong&gt;DRAM 缓存中的不命中比起 SRAM 缓存中的不命中要昂贵得多&lt;/strong&gt;。因此，与硬件对 SRAM 缓存相比，操作系统对 DRAM 缓存使用了更复杂精密的替换算法。（这些替换算法超出了我们的讨论范围）。最后，因为对磁盘的访问时间很长，&lt;strong&gt;DRAM 缓存总是使用写回，而不是直写&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;页表&#34;&gt;页表&lt;/h3&gt;
&lt;p&gt;虚拟内存系统可以完成以下这些功能，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;判定一个虚拟页是否缓存在 DRAM 中的某个地方；&lt;/li&gt;
&lt;li&gt;可以确定这个虚拟页存放在哪个物理页中；&lt;/li&gt;
&lt;li&gt;如果不命中，系统必须判断这个虚拟页存放在磁盘的哪个位置，在物理内存中选择一个牺牲页，并将虚拟页从磁盘复制到 DRAM 中，替换这个牺牲页。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些功能是由&lt;strong&gt;软硬件联合提供的&lt;/strong&gt;，包括操作系统软件、MMU（内存管理单元）中的地址翻译硬件和一个&lt;strong&gt;存放在物理内存中叫做页表&lt;/strong&gt;（page table）的数据结构。页表将虚拟页映射到物理页。每次地址翻译硬件将一个虚拟地址转换为物理地址时，都会读取页表。操作系统负责维护页表的内容，以及在磁盘与 DRAM 之间来回传送页。&lt;/p&gt;
&lt;p&gt;图 9-4 展示了一个页表的基本组织结构。页表就是一个页表条目（Page Table Entry，PTE）的数组。虚拟地址空间中的每个页在页表中一个固定偏移量处都有一个 PTE。&lt;/p&gt;
&lt;p&gt;PTE 由两部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有效位：表明了该虚拟页当前是否被缓存在 DRAM 中；&lt;/li&gt;
&lt;li&gt;地址：表示 DRAM 中相应的物理页的起始位置，这个物理页中缓存了该虚拟页。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208122157633.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208122157633.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;页命中与缺页&#34;&gt;页命中与缺页&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208130940717.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208130940717.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;l&lt;/p&gt;
&lt;p&gt;当 CPU 访问已被缓存的地址时，就叫做&lt;strong&gt;页命中&lt;/strong&gt;。如访问上图 VP2，虚拟地址索引到 PTE2，此时有效位为 1，地址翻译硬件就知道该地址被缓存了。&lt;/p&gt;
&lt;p&gt;当 CPU 访问未被缓存的地址时，会导致&lt;strong&gt;缺页&lt;/strong&gt;。如访问上图的 VP3，虚拟地址索引到 PTE3，此时有效位为 0，地址翻译硬件就知道该地址未被缓存，需要从磁盘中读取。&lt;/p&gt;
&lt;p&gt;这时会触发一个&lt;strong&gt;缺页异常&lt;/strong&gt;。&lt;strong&gt;缺页异常调用内核中的缺页异常处理程序&lt;/strong&gt;，该程序会选择一个牺牲页，在此例中就是存放在 PP 3 中的 VP 4。如果 VP 4 已经被修改了，那么内核就会将它复制回磁盘。无论哪种情况，内核都会修改 VP 4 的页表条目，反映出 VP 4 不再缓存在主存中这一事实。&lt;/p&gt;
&lt;p&gt;接下来，内核从磁盘复制 VP 3 到内存中的 PP 3，更新 PTE 3，随后返回。当异常处理程序返回时，它会&lt;strong&gt;重新启动导致缺页的指令&lt;/strong&gt;，该指令会把导致缺页的虚拟地址重发送到地址翻译硬件。但是现在，VP 3 已经缓存在主存中了，那么页命中也能由地址翻译硬件正常处理了。图 9-7 展示了在缺页之后我们的示例页表的状态。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131434643.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131434643.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;在虚拟内存的习惯说法中，块被称为页。在磁盘和内存之间传送页的活动叫做&lt;strong&gt;交换&lt;/strong&gt;（swapping）或者&lt;strong&gt;页面调度&lt;/strong&gt;（paging）。页从磁盘换入（或者页面调入）DRAM 和从 DRAM 换出（或者页面调出）磁盘。一直等待，直到最后时刻，也就是当有不命中发生时，才换入页面的这种策略称为按需页面调度（demand paging）。&lt;/p&gt;
&lt;h2 id=&#34;虚拟内存作为内存管理的工具&#34;&gt;虚拟内存作为内存管理的工具&lt;/h2&gt;
&lt;p&gt;之前我们只讨论了一个页表的情况，但是实际上操作系统为&lt;strong&gt;每个进程都分配了一个独立的页表&lt;/strong&gt;。多个虚拟页面可以映射到同一个共享物理页面上。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131441255.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131441255.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;按需页面调度和独立的虚拟地址空间的结合，对系统中内存的使用和管理造成了深远的影响。特别地，VM 简化了链接和加载、代码和数据共享，以及应用程序的内存分配。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;简化链接&lt;/strong&gt;。独立的地址空间允许每个进程的内存映像使用相同的基本格式，而&lt;strong&gt;不管代码和数据实际存放在物理内存的何处&lt;/strong&gt;。例如，一个给定的 Linux 系统上的每个进程都使用类似的内存格式。对于 64 位地址空间，代码段总是从虚拟地址 0x400000 开始。数据段跟在代码段之后，中间有一段符合要求的对齐空白。栈占据用户进程地址空间最高的部分，并向下生长。这样的一致性极大地简化了链接器的设计和实现，&lt;strong&gt;允许链接器生成完全链接的可执行文件，这些可执行文件是独立于物理内存中代码和数据的最终位置的&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;简化加载&lt;/strong&gt;。虚拟内存还使得容易向内存中加载可执行文件和共享对象文件。要把目标文件中 .text 和 .data 节加载到一个新创建的进程中，Linux 加载器为代码和数据段分配虚拟页，把它们标记为无效的（即未被缓存的），将页表条目指向目标文件中适当的位置。有趣的是，加载器从不从磁盘到内存实际复制任何数据。在每个页初次被引用时，要么是 CPU 取指令时引用的，要么是一条正在执行的指令引用一个内存位置时引用的，虚拟内存系统会按照需要自动地调入数据页。将一组连续的虚拟页映射到任意一个文件中的任意位置的表示法称作内存映射（memory mapping）。Linux 提供一个称为 mmap 的系统调用，允许应用程序自己做内存映射。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;简化共享&lt;/strong&gt;。独立地址空间为操作系统提供了一个管理用户进程和操作系统自身之间共享的一致机制。一般而言，每个进程都有自己私有的代码、数据、堆以及栈区域，是不和其他进程共享的。在这种情况中，操作系统创建页表，将相应的虚拟页映射到不连续的物理页面。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;简化内存分配&lt;/strong&gt;。虚拟内存为向用户进程提供一个简单的分配额外内存的机制。当一个运行在用户进程中的程序要求额外的堆空间时（如调用 malloc 的结果），&lt;strong&gt;操作系统分配一个适当数字（例如 k）个连续的虚拟内存页面，并且将它们映射到物理内存中任意位置的 k 个任意的物理页面&lt;/strong&gt;。由于页表工作的方式，操作系统没有必要分配 k 个连续的物理内存页面。&lt;strong&gt;页面可以随机地分散在物理内存中&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;虚拟内存作为内存保护的工具&#34;&gt;虚拟内存作为内存保护的工具&lt;/h2&gt;
&lt;p&gt;操作系统中的用户程序不应该修改只读的代码段，也不应该读取或者修改内核中的代码和数据结构或者访问私有的以及其他的进程的内存，如果无法对用户进程的内存访问进行限制，攻击者就可以访问和修改其他进程的内存影响系统的安全。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131522719.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131522719.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;通过在页表中添加页面的保护属性，可以让操作系统在页面被访问时进行检查，如果页面被保护为只读，则操作系统会报错。&lt;/p&gt;
&lt;p&gt;在图 9-10 这个示例中，每个 PTE 中已经添加了三个许可位。SUP 位表示进程是否必须运行在内核（超级用户）模式下才能访问该页。运行在内核模式中的进程可以访问任何页面，但是运行在用户模式中的进程只允许访问那些 SUP 为 0 的页面。READ 位和 WRITE 位控制对页面的读和写访问。例如，如果进程 i 运行在用户模式下，那么它有读 VP 0 和读写 VP 1 的权限。然而，不允许它访问 VP 2。&lt;/p&gt;
&lt;p&gt;如果一条指令违反了这些许可条件，那么 CPU 就触发一个一般保护故障，将控制传递给一个内核中的异常处理程序。Linux shell 一般将这种异常报告为&lt;strong&gt;段错误&lt;/strong&gt;（segmentation fault）。&lt;/p&gt;
&lt;h2 id=&#34;地址翻译&#34;&gt;地址翻译&lt;/h2&gt;
&lt;p&gt;基本参数&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;符号&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;描述&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$$\small N=2^n$$&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;虚拟地址空间中的地址数量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$$\small M=2^m$$&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;物理地址空间中的地址数量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;$$\small P=2^p$$&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;页的大小（字节）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;虚拟地址（VA）的组成部分&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;符号&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;描述&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;VPO&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;虚拟页面偏移量（字节）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;VPN&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;虚拟页号&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;TLBI&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;TLB 索引&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;TLBT&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;TLB 标记&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;物理地址（PA）的组成部分&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;符号&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;描述&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;PPO&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;物理页面偏移量（字节）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;PPN&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;物理页号&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;CO&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;缓冲块内的字节偏移量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;CI&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;高速缓存索引&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;CT&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;高速缓存标记&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131527131.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131527131.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;图 9-12 展示了 MMU 如何利用页表来实现地址翻译。CPU 中的一个控制寄存器，&lt;strong&gt;页表基址寄存器&lt;/strong&gt;（Page Table Base Register，PTBR）指向当前页表。$n$ 位的虚拟地址包含两个部分：一个 $p$ 位的&lt;strong&gt;虚拟页面偏移&lt;/strong&gt;（Virtual Page Offset，VPO）和一个$\small (n-p)$位的&lt;strong&gt;虚拟页号&lt;/strong&gt;（Virtual Page Number，VPN）。MMU 利用 VPN 来选择适当的 PTE。例如，VPN 0 选择 PTE 0，VPN 1 选择 PTE 1，以此类推。将页表条目中&lt;strong&gt;物理页号&lt;/strong&gt;（Physical Page Number，PPN）和虚拟地址中的 VP。串联起来，就得到相应的物理地址。注意，因为物理和虚拟页面都是 P 字节的，所以&lt;strong&gt;物理页面偏移（Physical Page Offset，PPO）和 VPO 是相同的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131527491.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131527491.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;图 9-13a 展示了当页面命中时，CPU 硬件执行的步骤。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第 1 步：处理器生成一个
虚拟地址，并把它传送给 MMU。&lt;/li&gt;
&lt;li&gt;第 2 步：MMU 生成 PTE 地址，并从高速缓存/主存请求得到它。&lt;/li&gt;
&lt;li&gt;第 3 步：高速缓存/主存向 MMU 返回 PTE。&lt;/li&gt;
&lt;li&gt;第 4 步：MMU 构造物理地址，并把它传送给高速缓存/主存。&lt;/li&gt;
&lt;li&gt;第 5 步：高速缓存/主存返回所请求的数据字给处理器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;页面命中完全是由硬件来处理的，与之不同的是，处理缺页要求硬件和操作系统内核协作完成，如图 9-13b 所示。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第 1 - 3 步：和图 9-13a 中的第 1 步到第 3 步相同。&lt;/li&gt;
&lt;li&gt;第 4 步：PTE 中的有效位是零，所以 MMU 触发了一次异常，传递 CPU 中的控制到操作系统内核中的缺页异常处理程序。&lt;/li&gt;
&lt;li&gt;第 5 步：缺页处理程序确定出物理内存中的牺牲页，如果这个页面已经被修改了，则把它换出到磁盘。&lt;/li&gt;
&lt;li&gt;第 6 步：缺页处理程序页面调入新的页面，并更新内存中的 PTE。&lt;/li&gt;
&lt;li&gt;第 7 步：缺页处理程序返回到原来的进程，再次执行导致缺页的指令。CPU 将引起缺页的虚拟地址重新发送给 MMU。因为虚拟页面现在缓存在物理内存中，所以就会命中，在 MMU 执行了图 9-13b 中的步骤之后，主存就会将所请求字返回给处理器。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;利用-tlb-加速地址翻译&#34;&gt;利用 TLB 加速地址翻译&lt;/h3&gt;
&lt;p&gt;每次 CPU 访问一个虚拟地址，MMU 就必须查找 PTE，以便将虚拟地址翻译为物理地址。在最糟糕的情况下，这会要求从内存多取一次数据，代价是几十到几百个周期。如果 PTE 碰巧缓存在 L1 中，那么开销就下降到 1 个或 2 个周期。为了消除这样的开销，在 MMU 中包括了一个关于 PTE 的小的缓存，称为&lt;strong&gt;翻译后备缓冲器&lt;/strong&gt;（Translation Lookaside Buffer，TLB）。&lt;/p&gt;
&lt;p&gt;TLB 是一个小的、虚拟寻址的缓存，其中&lt;strong&gt;每一行都保存着一个由单个 PTE 组成的块&lt;/strong&gt;。TLB 通常有高度的相联度。如图 9-15 所示，用于组选择和行匹配的索引和标记字段是从虚拟地址中的虚拟页号中提取出来的。如果 TLB 有$\small T = 2^t$个组，那么 &lt;strong&gt;TLB 索引&lt;/strong&gt;（TLBI）是由 VPN 的 $t$ 个最低位组成的，而 &lt;strong&gt;TLB 标记&lt;/strong&gt;（TLBT）是由 VPN 中剩余的位组成的。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131546427.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131546427.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;图 9-16a 展示了当 TLB 命中时（通常情况）所包括的步骤。这里的关键点是，所有的地址翻译步骤都是在芯片上的 MMU 中执行的，因此非常快。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第 1 步：CPU 产生一个虚拟地址。&lt;/li&gt;
&lt;li&gt;第 2 - 3 步：MMU 从 TLB 中取出相应的 PTE。&lt;/li&gt;
&lt;li&gt;第 4 步：MMU 将这个虚拟地址翻译成一个物理地址，并且将它发送到高速缓存/主存。&lt;/li&gt;
&lt;li&gt;第 5 步：高速缓存/主存将所请求的数据字返回给 CPU。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131547576.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131547576.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;当 TLB 不命中时，MMU 必须从 L1 缓存中取出相应的 PTE，如图 9-16b 所示。新取出的 PTE 存放在 TLB 中，可能会覆盖一个已经存在的条目。&lt;/p&gt;
&lt;h3 id=&#34;多级页表&#34;&gt;多级页表&lt;/h3&gt;
&lt;p&gt;32 位环境下，虚拟地址空间共 4GB。如果分成 4KB 一个页，那就是 1M 个页。每个页表项需要 4 个字节来存储，那么整个 4GB 空间的映射就需要 4MB 的内存来存储映射表。如果每个进程都有自己的映射表，100 个进程就需要 400MB 的内存。对于内核来讲，有点大了。&lt;/p&gt;
&lt;p&gt;页表中所有页表项必须提前建好，并且要求是连续的。如果不连续，就没有办法通过虚拟地址里面的页号找到对应的页表项了。&lt;/p&gt;
&lt;p&gt;那怎么办呢？我们可以试着将页表再分页，4G 的空间需要 4M 的页表来存储映射。我们把这 4M 分成 1K（1024）个 4K，每个 4K 又能放在一页里面，这样 1K 个 4K 就是 1K 个页，这 1K 个页也需要一个表进行管理，我们称为页目录表，这个页目录表里面有 1K 项，每项 4 个字节，页目录表大小也是 4K。&lt;/p&gt;
&lt;p&gt;页目录有 1K 项，用 10 位就可以表示访问页目录的哪一项。这一项其实对应的是一整页的页表项，也即 4K 的页表项。每个页表项也是 4 个字节，因而一整页的页表项是 1K 个。再用 10 位就可以表示访问页表项的哪一项，页表项中的一项对应的就是一个页，是存放数据的页，这个页的大小是 4K，用 12 位可以定位这个页内的任何一个位置。&lt;/p&gt;
&lt;p&gt;这样加起来正好 32 位，也就是用前 10 位定位到页目录表中的一项。将这一项对应的页表取出来共 1k 项，再用中间 10 位定位到页表中的一项，将这一项对应的存放数据的页取出来，再用最后 12 位定位到页中的具体位置访问数据。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129192245.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129192245.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;你可能会问，如果这样的话，映射 4GB 地址空间就需要 4MB+4KB 的内存，这样不是更大 了吗？当然如果页是满的，当时是更大了，但是，我们往往不会为一个进程分配那么多内 存。
比如说，上面图中，我们假设只给这个进程分配了一个数据页。如果只使用页表，也需要完 整的 1M 个页表项共 4M 的内存，但是如果使用了页目录，页目录需要 1K 个全部分配，占用内存 4K，但是里面只有一项使用了。到了页表项，只需要分配能够管理那个数据页的页表项页就可以了，也就是说，最多 4K，这样内存就节省多了&lt;/p&gt;
&lt;p&gt;当然对于 64 位的系统，两级肯定不够了，就变成了四级目录，分别是全局页目录项 PGD（Page Global Directory）、上层页目录项 PUD（Page Upper Directory）、中间
页目录项 PMD（Page Middle Directory）和页表项 PTE（Page Table Entry）。也就是一级页表，二级页表，三级页表，四级页表。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131820091.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131820091.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="为什么需要虚拟内存">为什么需要虚拟内存？</h2>
<p>CPU 访问内存的最自然的方式就是使用物理地址，这种方式称为<strong>物理寻址</strong>。1，计算机中并不是只有一个程序在运行，如果它们都是用物理寻址的方式，那么所有程序必须在链接之前确定好自己所用到的内存范围，否则两个程序就可能会发生冲突。2，程序大于内存的问题早在上世纪六十年代就出现，后来出现了<strong>覆盖技术</strong>（Overlay），把程序分割成许多片段。程序开始执行时，将覆盖管理模块装入内存，该管理模块立即装入并运行覆盖 0。执行完成后，覆盖 0 通知管理模块装入覆盖 1，或者占用覆盖 0 的上方位置（如果有空间），或者占用覆盖 0（如果没有空间）。把一个大程序分割成小的、模块化的片段是非常费时和枯燥的，并且易于出错。很少程序员擅长使用覆盖技术。</p>
<p>为了更加有效地管理内存并且少出错，现代系统提供了一种对主存的抽象概念，叫做<strong>虚拟内存</strong>(VM)。主要有三个功能：</p>
<ul>
<li>它将主存看成是一个存储在磁盘上的地址空间的高速缓存，在主存中只保存活动区域，并根据需要在磁盘和主存之间来回传送数据，通过这种方式，它<strong>高效地使用了主存</strong>。</li>
<li>它为每个进程提供了一致的地址空间，从而<strong>简化了内存管理</strong>。</li>
<li>它<strong>保护了每个进程</strong>的地址空间不被其他进程破坏。</li>
</ul>
<h2 id="什么是虚拟寻址">什么是虚拟寻址？</h2>
<p>如果主存被分为长度为$M$的单字节大小的数组，每个字节都对应一个物理地址，CPU 通过这个唯一的地址访问主存，这样的方式就是<strong>物理寻址</strong>。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202207212125636.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202207212125636.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>
现代处理器使用<strong>虚拟寻址</strong>的方式。CPU 通过生成的<strong>虚拟地址</strong>来访问内存，这个地址在送到内存之前会被转换成<strong>物理地址</strong>。这个过程称为<strong>地址翻译</strong>。CPU 芯片上叫做<strong>内存管理单元</strong>（Memory Management Unit, MMU）的专用硬件，利用存放在主存中的<strong>查询表</strong>来动态翻译虚拟地址，该表的内容由操作系统管理。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202207212128486.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202207212128486.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="虚拟内存作为缓存的工具">虚拟内存作为缓存的工具</h2>
<p>概念上而言，虚拟内存被组织成为一个由存放在磁盘上的 N 个连续的字节大小的单元组成的数组，也就是<strong>字节数组</strong>。每个字节都有一个唯一的虚拟地址作为数组的索引。磁盘上活动的数组内容被缓存在主存中。在存储器结构中，较低层次上的磁盘的数据被分割成块，这些块作为和较高层次的主存之间的传输单元。<strong>主存作为虚拟内存的缓存</strong>。</p>
<p>虚拟内存被分割为大小固定的块，这些块叫<strong>虚拟页</strong>（Virtual Page，VP），类似的物理内存也有<strong>物理页</strong>(Physical Page, PP)。虚拟页有三种不同的状态：</p>
<ul>
<li>未分配：VM 系统还未分配 (或者创建）的页。未分配的块没有任何数据和它们相关联，因此也就<strong>不占用任何磁盘空间</strong>。</li>
<li>已缓存：当前已缓存在物理内存中的已分配页。</li>
<li>未缓存：未缓存在物理内存中的已分配页。</li>
</ul>
<p>为了有助于清晰理解存储层次结构中不同的缓存概念，我们将使用术语<strong>SRAM</strong>缓存来表示位于 CPU 和主存之间的 Ll、L2 和 L3 <strong>高速缓存</strong>，并且用术语 <strong>DRAM</strong> 缓存来表示<strong>虚拟内存系统的缓存</strong>，它在主存中缓存虚拟页。</p>
<p>在存储层次结构中，DRAM 缓存的位置对它的组织结构有很大的影响。回想一下，DRAM 比 SRAM 要慢大约 10 倍，而磁盘要比 DRAM 慢大约 100000 多倍。因此，<strong>DRAM 缓存中的不命中比起 SRAM 缓存中的不命中要昂贵得多</strong>。因此，与硬件对 SRAM 缓存相比，操作系统对 DRAM 缓存使用了更复杂精密的替换算法。（这些替换算法超出了我们的讨论范围）。最后，因为对磁盘的访问时间很长，<strong>DRAM 缓存总是使用写回，而不是直写</strong>。</p>
<h3 id="页表">页表</h3>
<p>虚拟内存系统可以完成以下这些功能，</p>
<ul>
<li>判定一个虚拟页是否缓存在 DRAM 中的某个地方；</li>
<li>可以确定这个虚拟页存放在哪个物理页中；</li>
<li>如果不命中，系统必须判断这个虚拟页存放在磁盘的哪个位置，在物理内存中选择一个牺牲页，并将虚拟页从磁盘复制到 DRAM 中，替换这个牺牲页。</li>
</ul>
<p>这些功能是由<strong>软硬件联合提供的</strong>，包括操作系统软件、MMU（内存管理单元）中的地址翻译硬件和一个<strong>存放在物理内存中叫做页表</strong>（page table）的数据结构。页表将虚拟页映射到物理页。每次地址翻译硬件将一个虚拟地址转换为物理地址时，都会读取页表。操作系统负责维护页表的内容，以及在磁盘与 DRAM 之间来回传送页。</p>
<p>图 9-4 展示了一个页表的基本组织结构。页表就是一个页表条目（Page Table Entry，PTE）的数组。虚拟地址空间中的每个页在页表中一个固定偏移量处都有一个 PTE。</p>
<p>PTE 由两部分组成：</p>
<ul>
<li>有效位：表明了该虚拟页当前是否被缓存在 DRAM 中；</li>
<li>地址：表示 DRAM 中相应的物理页的起始位置，这个物理页中缓存了该虚拟页。</li>
</ul>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208122157633.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208122157633.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="页命中与缺页">页命中与缺页</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208130940717.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208130940717.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>l</p>
<p>当 CPU 访问已被缓存的地址时，就叫做<strong>页命中</strong>。如访问上图 VP2，虚拟地址索引到 PTE2，此时有效位为 1，地址翻译硬件就知道该地址被缓存了。</p>
<p>当 CPU 访问未被缓存的地址时，会导致<strong>缺页</strong>。如访问上图的 VP3，虚拟地址索引到 PTE3，此时有效位为 0，地址翻译硬件就知道该地址未被缓存，需要从磁盘中读取。</p>
<p>这时会触发一个<strong>缺页异常</strong>。<strong>缺页异常调用内核中的缺页异常处理程序</strong>，该程序会选择一个牺牲页，在此例中就是存放在 PP 3 中的 VP 4。如果 VP 4 已经被修改了，那么内核就会将它复制回磁盘。无论哪种情况，内核都会修改 VP 4 的页表条目，反映出 VP 4 不再缓存在主存中这一事实。</p>
<p>接下来，内核从磁盘复制 VP 3 到内存中的 PP 3，更新 PTE 3，随后返回。当异常处理程序返回时，它会<strong>重新启动导致缺页的指令</strong>，该指令会把导致缺页的虚拟地址重发送到地址翻译硬件。但是现在，VP 3 已经缓存在主存中了，那么页命中也能由地址翻译硬件正常处理了。图 9-7 展示了在缺页之后我们的示例页表的状态。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131434643.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131434643.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>在虚拟内存的习惯说法中，块被称为页。在磁盘和内存之间传送页的活动叫做<strong>交换</strong>（swapping）或者<strong>页面调度</strong>（paging）。页从磁盘换入（或者页面调入）DRAM 和从 DRAM 换出（或者页面调出）磁盘。一直等待，直到最后时刻，也就是当有不命中发生时，才换入页面的这种策略称为按需页面调度（demand paging）。</p>
<h2 id="虚拟内存作为内存管理的工具">虚拟内存作为内存管理的工具</h2>
<p>之前我们只讨论了一个页表的情况，但是实际上操作系统为<strong>每个进程都分配了一个独立的页表</strong>。多个虚拟页面可以映射到同一个共享物理页面上。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131441255.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131441255.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>按需页面调度和独立的虚拟地址空间的结合，对系统中内存的使用和管理造成了深远的影响。特别地，VM 简化了链接和加载、代码和数据共享，以及应用程序的内存分配。</p>
<ul>
<li><strong>简化链接</strong>。独立的地址空间允许每个进程的内存映像使用相同的基本格式，而<strong>不管代码和数据实际存放在物理内存的何处</strong>。例如，一个给定的 Linux 系统上的每个进程都使用类似的内存格式。对于 64 位地址空间，代码段总是从虚拟地址 0x400000 开始。数据段跟在代码段之后，中间有一段符合要求的对齐空白。栈占据用户进程地址空间最高的部分，并向下生长。这样的一致性极大地简化了链接器的设计和实现，<strong>允许链接器生成完全链接的可执行文件，这些可执行文件是独立于物理内存中代码和数据的最终位置的</strong>。</li>
<li><strong>简化加载</strong>。虚拟内存还使得容易向内存中加载可执行文件和共享对象文件。要把目标文件中 .text 和 .data 节加载到一个新创建的进程中，Linux 加载器为代码和数据段分配虚拟页，把它们标记为无效的（即未被缓存的），将页表条目指向目标文件中适当的位置。有趣的是，加载器从不从磁盘到内存实际复制任何数据。在每个页初次被引用时，要么是 CPU 取指令时引用的，要么是一条正在执行的指令引用一个内存位置时引用的，虚拟内存系统会按照需要自动地调入数据页。将一组连续的虚拟页映射到任意一个文件中的任意位置的表示法称作内存映射（memory mapping）。Linux 提供一个称为 mmap 的系统调用，允许应用程序自己做内存映射。</li>
<li><strong>简化共享</strong>。独立地址空间为操作系统提供了一个管理用户进程和操作系统自身之间共享的一致机制。一般而言，每个进程都有自己私有的代码、数据、堆以及栈区域，是不和其他进程共享的。在这种情况中，操作系统创建页表，将相应的虚拟页映射到不连续的物理页面。</li>
<li><strong>简化内存分配</strong>。虚拟内存为向用户进程提供一个简单的分配额外内存的机制。当一个运行在用户进程中的程序要求额外的堆空间时（如调用 malloc 的结果），<strong>操作系统分配一个适当数字（例如 k）个连续的虚拟内存页面，并且将它们映射到物理内存中任意位置的 k 个任意的物理页面</strong>。由于页表工作的方式，操作系统没有必要分配 k 个连续的物理内存页面。<strong>页面可以随机地分散在物理内存中</strong>。</li>
</ul>
<h2 id="虚拟内存作为内存保护的工具">虚拟内存作为内存保护的工具</h2>
<p>操作系统中的用户程序不应该修改只读的代码段，也不应该读取或者修改内核中的代码和数据结构或者访问私有的以及其他的进程的内存，如果无法对用户进程的内存访问进行限制，攻击者就可以访问和修改其他进程的内存影响系统的安全。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131522719.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131522719.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>通过在页表中添加页面的保护属性，可以让操作系统在页面被访问时进行检查，如果页面被保护为只读，则操作系统会报错。</p>
<p>在图 9-10 这个示例中，每个 PTE 中已经添加了三个许可位。SUP 位表示进程是否必须运行在内核（超级用户）模式下才能访问该页。运行在内核模式中的进程可以访问任何页面，但是运行在用户模式中的进程只允许访问那些 SUP 为 0 的页面。READ 位和 WRITE 位控制对页面的读和写访问。例如，如果进程 i 运行在用户模式下，那么它有读 VP 0 和读写 VP 1 的权限。然而，不允许它访问 VP 2。</p>
<p>如果一条指令违反了这些许可条件，那么 CPU 就触发一个一般保护故障，将控制传递给一个内核中的异常处理程序。Linux shell 一般将这种异常报告为<strong>段错误</strong>（segmentation fault）。</p>
<h2 id="地址翻译">地址翻译</h2>
<p>基本参数</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">符号</th>
					<th style="text-align: left">描述</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">$$\small N=2^n$$</td>
					<td style="text-align: left">虚拟地址空间中的地址数量</td>
			</tr>
			<tr>
					<td style="text-align: left">$$\small M=2^m$$</td>
					<td style="text-align: left">物理地址空间中的地址数量</td>
			</tr>
			<tr>
					<td style="text-align: left">$$\small P=2^p$$</td>
					<td style="text-align: left">页的大小（字节）</td>
			</tr>
	</tbody>
</table>
<p>虚拟地址（VA）的组成部分</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">符号</th>
					<th style="text-align: left">描述</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">VPO</td>
					<td style="text-align: left">虚拟页面偏移量（字节）</td>
			</tr>
			<tr>
					<td style="text-align: left">VPN</td>
					<td style="text-align: left">虚拟页号</td>
			</tr>
			<tr>
					<td style="text-align: left">TLBI</td>
					<td style="text-align: left">TLB 索引</td>
			</tr>
			<tr>
					<td style="text-align: left">TLBT</td>
					<td style="text-align: left">TLB 标记</td>
			</tr>
	</tbody>
</table>
<p>物理地址（PA）的组成部分</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">符号</th>
					<th style="text-align: left">描述</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">PPO</td>
					<td style="text-align: left">物理页面偏移量（字节）</td>
			</tr>
			<tr>
					<td style="text-align: left">PPN</td>
					<td style="text-align: left">物理页号</td>
			</tr>
			<tr>
					<td style="text-align: left">CO</td>
					<td style="text-align: left">缓冲块内的字节偏移量</td>
			</tr>
			<tr>
					<td style="text-align: left">CI</td>
					<td style="text-align: left">高速缓存索引</td>
			</tr>
			<tr>
					<td style="text-align: left">CT</td>
					<td style="text-align: left">高速缓存标记</td>
			</tr>
	</tbody>
</table>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131527131.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131527131.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>图 9-12 展示了 MMU 如何利用页表来实现地址翻译。CPU 中的一个控制寄存器，<strong>页表基址寄存器</strong>（Page Table Base Register，PTBR）指向当前页表。$n$ 位的虚拟地址包含两个部分：一个 $p$ 位的<strong>虚拟页面偏移</strong>（Virtual Page Offset，VPO）和一个$\small (n-p)$位的<strong>虚拟页号</strong>（Virtual Page Number，VPN）。MMU 利用 VPN 来选择适当的 PTE。例如，VPN 0 选择 PTE 0，VPN 1 选择 PTE 1，以此类推。将页表条目中<strong>物理页号</strong>（Physical Page Number，PPN）和虚拟地址中的 VP。串联起来，就得到相应的物理地址。注意，因为物理和虚拟页面都是 P 字节的，所以<strong>物理页面偏移（Physical Page Offset，PPO）和 VPO 是相同的</strong>。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131527491.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131527491.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>图 9-13a 展示了当页面命中时，CPU 硬件执行的步骤。</p>
<ul>
<li>第 1 步：处理器生成一个
虚拟地址，并把它传送给 MMU。</li>
<li>第 2 步：MMU 生成 PTE 地址，并从高速缓存/主存请求得到它。</li>
<li>第 3 步：高速缓存/主存向 MMU 返回 PTE。</li>
<li>第 4 步：MMU 构造物理地址，并把它传送给高速缓存/主存。</li>
<li>第 5 步：高速缓存/主存返回所请求的数据字给处理器。</li>
</ul>
<p>页面命中完全是由硬件来处理的，与之不同的是，处理缺页要求硬件和操作系统内核协作完成，如图 9-13b 所示。</p>
<ul>
<li>第 1 - 3 步：和图 9-13a 中的第 1 步到第 3 步相同。</li>
<li>第 4 步：PTE 中的有效位是零，所以 MMU 触发了一次异常，传递 CPU 中的控制到操作系统内核中的缺页异常处理程序。</li>
<li>第 5 步：缺页处理程序确定出物理内存中的牺牲页，如果这个页面已经被修改了，则把它换出到磁盘。</li>
<li>第 6 步：缺页处理程序页面调入新的页面，并更新内存中的 PTE。</li>
<li>第 7 步：缺页处理程序返回到原来的进程，再次执行导致缺页的指令。CPU 将引起缺页的虚拟地址重新发送给 MMU。因为虚拟页面现在缓存在物理内存中，所以就会命中，在 MMU 执行了图 9-13b 中的步骤之后，主存就会将所请求字返回给处理器。</li>
</ul>
<h3 id="利用-tlb-加速地址翻译">利用 TLB 加速地址翻译</h3>
<p>每次 CPU 访问一个虚拟地址，MMU 就必须查找 PTE，以便将虚拟地址翻译为物理地址。在最糟糕的情况下，这会要求从内存多取一次数据，代价是几十到几百个周期。如果 PTE 碰巧缓存在 L1 中，那么开销就下降到 1 个或 2 个周期。为了消除这样的开销，在 MMU 中包括了一个关于 PTE 的小的缓存，称为<strong>翻译后备缓冲器</strong>（Translation Lookaside Buffer，TLB）。</p>
<p>TLB 是一个小的、虚拟寻址的缓存，其中<strong>每一行都保存着一个由单个 PTE 组成的块</strong>。TLB 通常有高度的相联度。如图 9-15 所示，用于组选择和行匹配的索引和标记字段是从虚拟地址中的虚拟页号中提取出来的。如果 TLB 有$\small T = 2^t$个组，那么 <strong>TLB 索引</strong>（TLBI）是由 VPN 的 $t$ 个最低位组成的，而 <strong>TLB 标记</strong>（TLBT）是由 VPN 中剩余的位组成的。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131546427.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131546427.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>图 9-16a 展示了当 TLB 命中时（通常情况）所包括的步骤。这里的关键点是，所有的地址翻译步骤都是在芯片上的 MMU 中执行的，因此非常快。</p>
<ul>
<li>第 1 步：CPU 产生一个虚拟地址。</li>
<li>第 2 - 3 步：MMU 从 TLB 中取出相应的 PTE。</li>
<li>第 4 步：MMU 将这个虚拟地址翻译成一个物理地址，并且将它发送到高速缓存/主存。</li>
<li>第 5 步：高速缓存/主存将所请求的数据字返回给 CPU。</li>
</ul>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131547576.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131547576.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>当 TLB 不命中时，MMU 必须从 L1 缓存中取出相应的 PTE，如图 9-16b 所示。新取出的 PTE 存放在 TLB 中，可能会覆盖一个已经存在的条目。</p>
<h3 id="多级页表">多级页表</h3>
<p>32 位环境下，虚拟地址空间共 4GB。如果分成 4KB 一个页，那就是 1M 个页。每个页表项需要 4 个字节来存储，那么整个 4GB 空间的映射就需要 4MB 的内存来存储映射表。如果每个进程都有自己的映射表，100 个进程就需要 400MB 的内存。对于内核来讲，有点大了。</p>
<p>页表中所有页表项必须提前建好，并且要求是连续的。如果不连续，就没有办法通过虚拟地址里面的页号找到对应的页表项了。</p>
<p>那怎么办呢？我们可以试着将页表再分页，4G 的空间需要 4M 的页表来存储映射。我们把这 4M 分成 1K（1024）个 4K，每个 4K 又能放在一页里面，这样 1K 个 4K 就是 1K 个页，这 1K 个页也需要一个表进行管理，我们称为页目录表，这个页目录表里面有 1K 项，每项 4 个字节，页目录表大小也是 4K。</p>
<p>页目录有 1K 项，用 10 位就可以表示访问页目录的哪一项。这一项其实对应的是一整页的页表项，也即 4K 的页表项。每个页表项也是 4 个字节，因而一整页的页表项是 1K 个。再用 10 位就可以表示访问页表项的哪一项，页表项中的一项对应的就是一个页，是存放数据的页，这个页的大小是 4K，用 12 位可以定位这个页内的任何一个位置。</p>
<p>这样加起来正好 32 位，也就是用前 10 位定位到页目录表中的一项。将这一项对应的页表取出来共 1k 项，再用中间 10 位定位到页表中的一项，将这一项对应的存放数据的页取出来，再用最后 12 位定位到页中的具体位置访问数据。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129192245.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129192245.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>你可能会问，如果这样的话，映射 4GB 地址空间就需要 4MB+4KB 的内存，这样不是更大 了吗？当然如果页是满的，当时是更大了，但是，我们往往不会为一个进程分配那么多内 存。
比如说，上面图中，我们假设只给这个进程分配了一个数据页。如果只使用页表，也需要完 整的 1M 个页表项共 4M 的内存，但是如果使用了页目录，页目录需要 1K 个全部分配，占用内存 4K，但是里面只有一项使用了。到了页表项，只需要分配能够管理那个数据页的页表项页就可以了，也就是说，最多 4K，这样内存就节省多了</p>
<p>当然对于 64 位的系统，两级肯定不够了，就变成了四级目录，分别是全局页目录项 PGD（Page Global Directory）、上层页目录项 PUD（Page Upper Directory）、中间
页目录项 PMD（Page Middle Directory）和页表项 PTE（Page Table Entry）。也就是一级页表，二级页表，三级页表，四级页表。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131820091.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208131820091.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>C 语言 getopt() 函数的用法</title>
      <link>https://lifeislife.cn/posts/c%E8%AF%AD%E8%A8%80getopt-%E5%87%BD%E6%95%B0%E7%9A%84%E7%94%A8%E6%B3%95/</link>
      <pubDate>Sat, 16 Jul 2022 22:42:03 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/c%E8%AF%AD%E8%A8%80getopt-%E5%87%BD%E6%95%B0%E7%9A%84%E7%94%A8%E6%B3%95/</guid>
      <description>&lt;p&gt;在做&lt;a href=&#34;https://dunky-z.github.io/2022/07/11/CSAPP-LAB-Cache-Lab/&#34;&gt;CSAPP_LAB-Cache Lab&lt;/a&gt;时，实验要求对输入参数进行处理，如程序&lt;code&gt;csim&lt;/code&gt;执行需要 4 个参数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./csim -s &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; -E &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; -b &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; -t &amp;lt;tracefile&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原先想通过字符串解析，一个个处理，但是看到了其他参考代码后发现了一个更简单的方法，可以通过&lt;code&gt;getopt()&lt;/code&gt;函数来解析参数。&lt;/p&gt;
&lt;p&gt;函数的功能：解析命令行参数。
头文件 &lt;code&gt;#include &amp;lt;unistd.h&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在学习函数前需要了解与该函数相关的四个变量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;int opterr&lt;/code&gt;：控制是否输出错误；
如果此变量的值非零，则 &lt;code&gt;getopt&lt;/code&gt; 在遇到未知选项字符或缺少必需参数的选项时将错误消息打印到标准错误流 (终端)。该值默认为非零。如果将此变量设置为零，&lt;code&gt;getopt&lt;/code&gt; 不会打印任何消息，但仍会返回问号&lt;code&gt;?&lt;/code&gt;提示错误。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;int optopt&lt;/code&gt;：保存未知的选项；
当 &lt;code&gt;getopt&lt;/code&gt; 遇到未知选项字符或缺少必需参数的选项时，它将该选项字符存储在此变量中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;int optind&lt;/code&gt;：指向下一个要处理的参数；
此变量由 &lt;code&gt;getopt&lt;/code&gt; 设置为要处理的 &lt;code&gt;argv&lt;/code&gt; 数组的下一个元素的索引。一旦 &lt;code&gt;getopt&lt;/code&gt; 找到所有选项参数，就可以使用此变量来确定其余非选项参数的开始位置。该变量的初始值为 1。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;char * optarg&lt;/code&gt;：保存选项参数；
对于那些接受参数的选项，此变量由 &lt;code&gt;getopt&lt;/code&gt; 设置为指向选项参数的值。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;函数原型：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;getopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;options&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参数解析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参数&lt;code&gt;argc&lt;/code&gt; 和&lt;code&gt;argv&lt;/code&gt; 是由&lt;code&gt;main()&lt;/code&gt;传递的参数个数和内容。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;options&lt;/code&gt; 参数是一个字符串，它指定对该程序有效的选项字符。此字符串中的选项字符后面可以跟一个冒号（&lt;code&gt;:&lt;/code&gt;），表示它需要一个&lt;strong&gt;必需的参数&lt;/strong&gt;，这个参数可以与选项连写也可以空格分开，如&lt;code&gt;-a13 or  -a 13&lt;/code&gt;。如果选项字符后跟两个冒号（&lt;code&gt;::&lt;/code&gt;），则其参数是&lt;strong&gt;可选的&lt;/strong&gt;，如果有参数，那么参数不能与选项分割，如只能写成&lt;code&gt;-a13&lt;/code&gt;而不能写成&lt;code&gt;-a 13&lt;/code&gt;；这是一个 GNU 扩展。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实例：&lt;/p&gt;
&lt;p&gt;下面是一个示例，展示了通常如何使用 &lt;code&gt;getopt&lt;/code&gt;。需要注意的关键点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通常，&lt;code&gt;getopt&lt;/code&gt; 在循环中被调用。当 &lt;code&gt;getopt&lt;/code&gt; 返回 &lt;code&gt;-1&lt;/code&gt; 表示没有更多选项存在时，循环终止。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;switch&lt;/code&gt; 语句用于调度 &lt;code&gt;getopt&lt;/code&gt; 的返回值。在典型使用中，每种情况只设置一个稍后在程序中使用的变量。&lt;/li&gt;
&lt;li&gt;第二个循环用于处理剩余的非选项参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;ctype.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;opterr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;getopt&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;abc:&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;optopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Option -%c requires an argument.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;optopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;isprint&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;optopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Unknown option `-%c&amp;#39;.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;optopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   &lt;span class=&#34;s&#34;&gt;&amp;#34;Unknown option character `&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;x%x&amp;#39;.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   &lt;span class=&#34;n&#34;&gt;optopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;abort&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;aflag = %d, bflag = %d, cvalue = %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;optind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Non-option argument %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以下是一些示例，展示了该程序使用不同的参数组合打印的内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 选项可以用空格分割
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 也可以连写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ab&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 必选参数，可以用空格分割
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 必选参数，可以连写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cfoo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 没有对应的选项
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Non&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argument&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// -a选项没有需要处理的参数，所以arg1无法处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Non&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argument&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Non&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argument&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Non&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argument&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;testopt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;aflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bflag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cvalue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Non&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argument&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.csdn.net/huangxiaohu_coder/article/details/7475156&#34;&gt;原来命令行参数处理可以这么写-getopt？_huangxiaohu_coder 的博客-CSDN 博客&lt;/a&gt;
&lt;a href=&#34;https://www.cnblogs.com/qingergege/p/5914218.html&#34;&gt;Linux 下 getopt() 函数的简单使用 - 青儿哥哥 - 博客园&lt;/a&gt;
&lt;a href=&#34;http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html&#34;&gt;Using Getopt (The GNU C Library)&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>在做<a href="https://dunky-z.github.io/2022/07/11/CSAPP-LAB-Cache-Lab/">CSAPP_LAB-Cache Lab</a>时，实验要求对输入参数进行处理，如程序<code>csim</code>执行需要 4 个参数：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./csim -s <span class="m">4</span> -E <span class="m">6</span> -b <span class="m">4</span> -t &lt;tracefile&gt;
</span></span></code></pre></div><p>原先想通过字符串解析，一个个处理，但是看到了其他参考代码后发现了一个更简单的方法，可以通过<code>getopt()</code>函数来解析参数。</p>
<p>函数的功能：解析命令行参数。
头文件 <code>#include &lt;unistd.h&gt;</code></p>
<p>在学习函数前需要了解与该函数相关的四个变量：</p>
<ul>
<li>
<p><code>int opterr</code>：控制是否输出错误；
如果此变量的值非零，则 <code>getopt</code> 在遇到未知选项字符或缺少必需参数的选项时将错误消息打印到标准错误流 (终端)。该值默认为非零。如果将此变量设置为零，<code>getopt</code> 不会打印任何消息，但仍会返回问号<code>?</code>提示错误。</p>
</li>
<li>
<p><code>int optopt</code>：保存未知的选项；
当 <code>getopt</code> 遇到未知选项字符或缺少必需参数的选项时，它将该选项字符存储在此变量中。</p>
</li>
<li>
<p><code>int optind</code>：指向下一个要处理的参数；
此变量由 <code>getopt</code> 设置为要处理的 <code>argv</code> 数组的下一个元素的索引。一旦 <code>getopt</code> 找到所有选项参数，就可以使用此变量来确定其余非选项参数的开始位置。该变量的初始值为 1。</p>
</li>
<li>
<p><code>char * optarg</code>：保存选项参数；
对于那些接受参数的选项，此变量由 <code>getopt</code> 设置为指向选项参数的值。</p>
</li>
</ul>
<p>函数原型：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">getopt</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span> <span class="k">const</span> <span class="n">argv</span><span class="p">[],</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">options</span><span class="p">);</span>
</span></span></code></pre></div><p>参数解析：</p>
<ul>
<li>参数<code>argc</code> 和<code>argv</code> 是由<code>main()</code>传递的参数个数和内容。</li>
<li><code>options</code> 参数是一个字符串，它指定对该程序有效的选项字符。此字符串中的选项字符后面可以跟一个冒号（<code>:</code>），表示它需要一个<strong>必需的参数</strong>，这个参数可以与选项连写也可以空格分开，如<code>-a13 or  -a 13</code>。如果选项字符后跟两个冒号（<code>::</code>），则其参数是<strong>可选的</strong>，如果有参数，那么参数不能与选项分割，如只能写成<code>-a13</code>而不能写成<code>-a 13</code>；这是一个 GNU 扩展。</li>
</ul>
<p>实例：</p>
<p>下面是一个示例，展示了通常如何使用 <code>getopt</code>。需要注意的关键点是：</p>
<ul>
<li>通常，<code>getopt</code> 在循环中被调用。当 <code>getopt</code> 返回 <code>-1</code> 表示没有更多选项存在时，循环终止。</li>
<li><code>switch</code> 语句用于调度 <code>getopt</code> 的返回值。在典型使用中，每种情况只设置一个稍后在程序中使用的变量。</li>
<li>第二个循环用于处理剩余的非选项参数。</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;ctype.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">aflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">char</span> <span class="o">*</span><span class="n">cvalue</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">index</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">c</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">opterr</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="p">((</span><span class="n">c</span> <span class="o">=</span> <span class="nf">getopt</span> <span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="s">&#34;abc:&#34;</span><span class="p">))</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">switch</span> <span class="p">(</span><span class="n">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">case</span> <span class="sc">&#39;a&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">aflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">case</span> <span class="sc">&#39;b&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">bflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">case</span> <span class="sc">&#39;c&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">cvalue</span> <span class="o">=</span> <span class="n">optarg</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">case</span> <span class="sc">&#39;?&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">optopt</span> <span class="o">==</span> <span class="sc">&#39;c&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="nf">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;Option -%c requires an argument.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">optopt</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nf">isprint</span> <span class="p">(</span><span class="n">optopt</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">          <span class="nf">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;Unknown option `-%c&#39;.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">optopt</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span>
</span></span><span class="line"><span class="cl">          <span class="nf">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                   <span class="s">&#34;Unknown option character `</span><span class="se">\\</span><span class="s">x%x&#39;.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                   <span class="n">optopt</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="nf">abort</span> <span class="p">();</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nf">printf</span> <span class="p">(</span><span class="s">&#34;aflag = %d, bflag = %d, cvalue = %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="n">aflag</span><span class="p">,</span> <span class="n">bflag</span><span class="p">,</span> <span class="n">cvalue</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">for</span> <span class="p">(</span><span class="n">index</span> <span class="o">=</span> <span class="n">optind</span><span class="p">;</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="n">argc</span><span class="p">;</span> <span class="n">index</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span> <span class="p">(</span><span class="s">&#34;Non-option argument %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="n">index</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>以下是一些示例，展示了该程序使用不同的参数组合打印的内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="p">(</span><span class="n">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 选项可以用空格分割
</span></span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="o">-</span><span class="n">a</span> <span class="o">-</span><span class="n">b</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="p">(</span><span class="n">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 也可以连写
</span></span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="o">-</span><span class="n">ab</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="p">(</span><span class="n">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 必选参数，可以用空格分割
</span></span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="o">-</span><span class="n">c</span> <span class="n">foo</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="n">foo</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 必选参数，可以连写
</span></span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="o">-</span><span class="n">cfoo</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="n">foo</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 没有对应的选项
</span></span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="n">arg1</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="p">(</span><span class="n">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">Non</span><span class="o">-</span><span class="n">option</span> <span class="n">argument</span> <span class="n">arg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// -a选项没有需要处理的参数，所以arg1无法处理
</span></span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="o">-</span><span class="n">a</span> <span class="n">arg1</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="p">(</span><span class="n">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">Non</span><span class="o">-</span><span class="n">option</span> <span class="n">argument</span> <span class="n">arg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="o">-</span><span class="n">c</span> <span class="n">foo</span> <span class="n">arg1</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="n">foo</span>
</span></span><span class="line"><span class="cl"><span class="n">Non</span><span class="o">-</span><span class="n">option</span> <span class="n">argument</span> <span class="n">arg1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="o">-</span><span class="n">a</span> <span class="o">--</span> <span class="o">-</span><span class="n">b</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="p">(</span><span class="n">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">Non</span><span class="o">-</span><span class="n">option</span> <span class="n">argument</span> <span class="o">-</span><span class="n">b</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">%</span> <span class="n">testopt</span> <span class="o">-</span><span class="n">a</span> <span class="o">-</span>
</span></span><span class="line"><span class="cl"><span class="n">aflag</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">bflag</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">cvalue</span> <span class="o">=</span> <span class="p">(</span><span class="n">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">Non</span><span class="o">-</span><span class="n">option</span> <span class="n">argument</span> <span class="o">-</span>
</span></span></code></pre></div><h2 id="参考资料">参考资料</h2>
<p><a href="https://blog.csdn.net/huangxiaohu_coder/article/details/7475156">原来命令行参数处理可以这么写-getopt？_huangxiaohu_coder 的博客-CSDN 博客</a>
<a href="https://www.cnblogs.com/qingergege/p/5914218.html">Linux 下 getopt() 函数的简单使用 - 青儿哥哥 - 博客园</a>
<a href="http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html">Using Getopt (The GNU C Library)</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>构建和测试 RISC-V 架构下启用 ACPI 的内核</title>
      <link>https://lifeislife.cn/posts/%E6%9E%84%E5%BB%BA%E5%92%8C%E6%B5%8B%E8%AF%95risc-v%E6%9E%B6%E6%9E%84%E4%B8%8B%E5%90%AF%E7%94%A8acpi%E7%9A%84%E5%86%85%E6%A0%B8/</link>
      <pubDate>Tue, 12 Jul 2022 15:06:51 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%9E%84%E5%BB%BA%E5%92%8C%E6%B5%8B%E8%AF%95risc-v%E6%9E%B6%E6%9E%84%E4%B8%8B%E5%90%AF%E7%94%A8acpi%E7%9A%84%E5%86%85%E6%A0%B8/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;参考自&lt;a href=&#34;https://github.com/riscv-non-isa/riscv-acpi/wiki/PoC-:-How-to-build-and-test-ACPI-enabled-kernel&#34;&gt;PoC : How to build and test ACPI enabled kernel · riscv-non-isa/riscv-acpi Wiki&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;准备环境及工具链&#34;&gt;准备环境及工具链&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;安装 RISC-V 工具链，需下载原发行版。好在 apt 可以安装。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果报错：riscv64-linux-gnu-gcc: error: unrecognized command line option ‘-mno-relax’; did you mean ‘-Wno-vla’?，多半是工具链原因，请按照以下方法安装！！！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt remove gcc-riscv64-linux-gnu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install gcc-8-riscv64-linux-gnu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装必要的三方库，以下为Ubuntu下的命令，其他平台可以参考&lt;a href=&#34;https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html#prerequisites&#34;&gt;这个文档&lt;/a&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                gawk build-essential bison flex texinfo gperf libtool patchutils bc &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                zlib1g-dev libexpat-dev git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;下载源码&#34;&gt;下载源码&lt;/h2&gt;
&lt;p&gt;可能无法一次搭建成功，一些环境变量会经常用到，所以干脆把所有环境变量放到&lt;code&gt;.bashrc&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 添加以下内容&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;WORK_DIR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;~/riscv64-acpi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;GCC5_RISCV64_PREFIX&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-elf-
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;MAINSPACE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;~/riscv64-acpi/tianocore
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;PACKAGES_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$MAINSPACE&lt;/span&gt;/edk2:&lt;span class=&#34;nv&#34;&gt;$MAINSPACE&lt;/span&gt;/edk2-platforms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;EDK_TOOLS_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$MAINSPACE&lt;/span&gt;/edk2/BaseTools
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;首先，创建一个工作目录，我们将在其中下载并构建所有源代码。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;WORK_DIR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$PWD&lt;/span&gt;/riscv64-acpi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后下载所有需要的源，它们是：&lt;a href=&#34;https://github.com/ventanamicro/qemu/tree/dev-upstream&#34;&gt;qemu&lt;/a&gt;、&lt;a href=&#34;https://github.com/ventanamicro/opensbi/tree/dev-upstream&#34;&gt;opensbi&lt;/a&gt;、&lt;a href=&#34;https://github.com/ventanamicro/edk2/tree/dev-upstream&#34;&gt;edk2&lt;/a&gt;、&lt;a href=&#34;https://github.com/ventanamicro/edk2-platforms/tree/dev-upstream&#34;&gt;edk2-platforms&lt;/a&gt;、&lt;a href=&#34;https://github.com/ventanamicro/linux/tree/dev-upstream&#34;&gt;linux&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;下载地址更换成了加速镜像源，原来地址下载太慢，容易中断。下载地址更换成了加速镜像源，原来地址下载太慢，容易中断。有两个项目包含子模块，下载容易出错，所以&lt;code&gt;--depth=1&lt;/code&gt;舍弃了多余的提交记录。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone --branch dev-upstream  https://hub.fastgit.xyz/ventanamicro/qemu.git qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone --branch dev-upstream  https://hub.fastgit.xyz/ventanamicro/opensbi.git opensbi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone --branch dev-upstream --recurse-submodules --depth&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;  https://hub.fastgit.xyz/ventanamicro/edk2.git tianocore/edk2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone --branch dev-upstream --recurse-submodules --depth&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;  https://hub.fastgit.xyz/ventanamicro/edk2-platforms.git  tianocore/edk2-platforms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone --branch dev-upstream  https://hub.fastgit.xyz/ventanamicro/linux.git linux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;编译构建&#34;&gt;编译构建&lt;/h2&gt;
&lt;h3 id=&#34;qemu&#34;&gt;QEMU&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./configure --target-list&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-softmmu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make -j &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;nproc&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;opensbi&#34;&gt;OPENSBI&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;此处我们使用以&lt;code&gt;riscv64-unknown-elf-&lt;/code&gt;为前缀的版本，则表示该版本GCC工具链会使用newlib作为C运行库。原文使用&lt;code&gt;riscv64-linux-gnu-&lt;/code&gt;，表示GCC工具链会使用Linux的Glibc作为C运行库。但是本人未编译成功。故后面编译工具均使用&lt;code&gt;riscv64-unknown-elf-&lt;/code&gt;，与原文不同。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/opensbi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;ARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-elf- make &lt;span class=&#34;nv&#34;&gt;PLATFORM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;generic
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;edk2-固件&#34;&gt;EDK2 固件&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;此处原文里设置了一些环境变量在开头我们设置了，请不要重新设置，尤其不能&lt;code&gt;export WORKSPACE=pwd&lt;/code&gt;，因为与源码脚本的WORKSPACE冲突。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/tianocore
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; edk2/edksetup.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make -C edk2/BaseTools clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make -C edk2/BaseTools
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make -C edk2/BaseTools/Source/C
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; edk2/edksetup.sh BaseTools
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 原文使用 -buildtarget RELEASE。但是提示 Not supported target RELEASE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;build -a RISCV64 -b DEBUG -D &lt;span class=&#34;nv&#34;&gt;FW_BASE_ADDRESS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x80200000 -D EDK2_PAYLOAD_OFFSET -p Platform/Qemu/RiscvVirt/RiscvVirt.dsc -t GCC5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;error&#34;&gt;ERROR&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;StoreCurrentConfiguration:7: no such file or directory: /home/user/riscv64-acpi/tianocore/Conf/BuildEnv.sh&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不要设置&lt;code&gt;export WORKSPACE=pwd&lt;/code&gt;！！！如果所有方法都不可行，直接把路径写死&lt;code&gt;export CONF_PATH=$WORK_DIR/tianocore/edk2/Conf&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;uuid/uuid.h: No such file or directory&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install uuid-dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Not supported target RELEASE&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 将build命令改为如下，使用DEBUG版本。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;build -a RISCV64 -b DEBUG -D &lt;span class=&#34;nv&#34;&gt;FW_BASE_ADDRESS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x80200000 -D EDK2_PAYLOAD_OFFSET -p Platform/Qemu/RiscvVirt/RiscvVirt.dsc -t GCC5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;linux&#34;&gt;Linux&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/linux
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;ARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-elf- defconfig
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;ARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-elf- -j &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;nproc&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;rootfs&#34;&gt;Rootfs&lt;/h3&gt;
&lt;p&gt;您可以使用您选择的任何 rootfs。此示例使用 buildroot。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;此步耗时较久，与网络环境有关，如果网络不好可能按小时算。容易中断，需要重新下载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://hub.fastgit.xyz/buildroot/buildroot.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/buildroot
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make qemu_riscv64_virt_defconfig
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make rootfs-cpio
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;创建-efi-分区并复制文件&#34;&gt;创建 EFI 分区并复制文件&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fallocate -l 512M efi.img
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sgdisk -n 1:34: -t 1:EF00 &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/efi.img
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo losetup -fP &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/efi.img
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;loopdev&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;losetup -j &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/efi.img &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; awk -F: &lt;span class=&#34;s1&#34;&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;efi_part&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$loopdev&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;p1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo mkfs.msdos &lt;span class=&#34;nv&#34;&gt;$efi_part&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p /tmp/mnt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo mount &lt;span class=&#34;nv&#34;&gt;$efi_part&lt;/span&gt; /tmp/mnt/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo cp &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/linux/arch/riscv/boot/Image /tmp/mnt/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo umount /tmp/mnt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo losetup -D &lt;span class=&#34;nv&#34;&gt;$loopdev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;运行&#34;&gt;运行&lt;/h2&gt;
&lt;h3 id=&#34;使用-virtio-blk-磁盘&#34;&gt;使用 virtio-blk 磁盘&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;原文参数&lt;code&gt;-drive file=$WORK_DIR/buildroot/output/images/rootfs.ext2,format=raw,id=hd0&lt;/code&gt;需要更改如下。因为在编译 Rootfs 时的命令是&lt;code&gt;make rootfs-cpio&lt;/code&gt;所以生成的是&lt;code&gt;rootfs.cpio&lt;/code&gt;。无法找到&lt;code&gt;rootfs.ext2&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/qemu/build/qemu-system-riscv64 -nographic &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-machine virt,aclint&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;on,aia&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;aplic-imsic,acpi&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;on -cpu rv64,sscofpmf&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt; -smp &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt;  -m 2G  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-bios &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/opensbi/build/platform/generic/firmware/fw_jump.elf &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-kernel &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/tianocore/Build/RiscvVirt/DEBUG_GCC5/FV/RISCVVIRT.fd  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-drive &lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/buildroot/output/images/rootfs.cpio,format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;raw,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hd0 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device virtio-blk-device,drive&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hd0 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-drive &lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/efi.img,format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;raw,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hd1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device virtio-blk-device,drive&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hd1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device virtio-net-device,netdev&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;usernet &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-netdev user,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;usernet,hostfwd&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;tcp::9990-:22
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;error-1&#34;&gt;ERROR&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;无法找到&lt;code&gt;rootfs.ext2&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 因为在编译 Rootfs 时的命令是 make rootfs-cpio 所以生成的是 rootfs.cpio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 原文参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-drive &lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/buildroot/output/images/rootfs.ext2,format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;raw,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hd0 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 修改为&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-drive &lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/buildroot/output/images/rootfs.cpio,format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;raw,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hd0 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;无法找到&lt;code&gt;RISCVVIRT.fd&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 因为编译 EDK2 固件时，参数是-b DEBUG 版本，原文是 RELEASE 版本，这两个版本路径不一样，所以找不到&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 原文参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-kernel &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/tianocore/Build/RiscvVirt/RELEASE_GCC5/FV/RISCVVIRT.fd  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 修改为&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-kernel &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/tianocore/Build/RiscvVirt/DEBUG_GCC5/FV/RISCVVIRT.fd  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At EFI Shell:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Shell&amp;gt; fs0:&lt;span class=&#34;se&#34;&gt;\I&lt;/span&gt;mage &lt;span class=&#34;nv&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/vdb &lt;span class=&#34;nv&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;ttyS0 rootwait earlycon
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220713153915.bmp&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220713153915.bmp&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220713153932.bmp&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220713153932.bmp&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;使用-virtio-scsi-磁盘&#34;&gt;使用 virtio-scsi 磁盘&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/qemu/build/qemu-system-riscv64 -nographic &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-machine virt,aclint&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;on,aia&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;aplic-imsic,acpi&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;on -cpu rv64,ssofpmf&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt; -smp &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt;  -m 2G &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-bios &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/opensbi/build/platform/generic/firmware/fw_jump.elf &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-kernel &lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/tianocore/Build/RiscvVirt/DEBUG_GCC5/FV/RISCVVIRT.fd  &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device virtio-scsi-pci,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;scsi0,num_queues&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device scsi-hd,drive&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;drive0,bus&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;scsi0.0,channel&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0,scsi-id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0,lun&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-drive &lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/buildroot/output/images/rootfs.cpio,format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;raw,if&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;none,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;drive0 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device virtio-scsi-pci,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;scsi1,num_queues&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device scsi-hd,drive&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;drive1,bus&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;scsi0.0,channel&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0,scsi-id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1,lun&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-drive &lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$WORK_DIR&lt;/span&gt;/efi.img,format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;raw,if&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;none,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;drive1 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device virtio-net-device,netdev&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;usernet &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-netdev user,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;usernet,hostfwd&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;tcp::9990-:22
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At EFI Shell:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Shell&amp;gt; fs0:&lt;span class=&#34;se&#34;&gt;\I&lt;/span&gt;mage &lt;span class=&#34;nv&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/sda &lt;span class=&#34;nv&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;ttyS0 rootwait earlycon
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>参考自<a href="https://github.com/riscv-non-isa/riscv-acpi/wiki/PoC-:-How-to-build-and-test-ACPI-enabled-kernel">PoC : How to build and test ACPI enabled kernel · riscv-non-isa/riscv-acpi Wiki</a></p>
</blockquote>
<h2 id="准备环境及工具链">准备环境及工具链</h2>
<ol>
<li>
<p>安装 RISC-V 工具链，需下载原发行版。好在 apt 可以安装。</p>
<blockquote>
<p>如果报错：riscv64-linux-gnu-gcc: error: unrecognized command line option ‘-mno-relax’; did you mean ‘-Wno-vla’?，多半是工具链原因，请按照以下方法安装！！！</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo apt remove gcc-riscv64-linux-gnu
</span></span><span class="line"><span class="cl">sudo apt install gcc-8-riscv64-linux-gnu
</span></span></code></pre></div></li>
<li>
<p>安装必要的三方库，以下为Ubuntu下的命令，其他平台可以参考<a href="https://risc-v-getting-started-guide.readthedocs.io/en/latest/linux-qemu.html#prerequisites">这个文档</a>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev <span class="se">\
</span></span></span><span class="line"><span class="cl">                gawk build-essential bison flex texinfo gperf libtool patchutils bc <span class="se">\
</span></span></span><span class="line"><span class="cl">                zlib1g-dev libexpat-dev git
</span></span></code></pre></div></li>
</ol>
<h2 id="下载源码">下载源码</h2>
<p>可能无法一次搭建成功，一些环境变量会经常用到，所以干脆把所有环境变量放到<code>.bashrc</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">vim ~/.bashrc
</span></span><span class="line"><span class="cl"><span class="c1"># 添加以下内容</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">WORK_DIR</span><span class="o">=</span>~/riscv64-acpi
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">GCC5_RISCV64_PREFIX</span><span class="o">=</span>riscv64-unknown-elf-
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">MAINSPACE</span><span class="o">=</span>~/riscv64-acpi/tianocore
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PACKAGES_PATH</span><span class="o">=</span><span class="nv">$MAINSPACE</span>/edk2:<span class="nv">$MAINSPACE</span>/edk2-platforms
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">EDK_TOOLS_PATH</span><span class="o">=</span><span class="nv">$MAINSPACE</span>/edk2/BaseTools
</span></span></code></pre></div><p>首先，创建一个工作目录，我们将在其中下载并构建所有源代码。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">source</span> ~/.bashrc
</span></span><span class="line"><span class="cl"><span class="nv">WORK_DIR</span><span class="o">=</span><span class="nv">$PWD</span>/riscv64-acpi
</span></span><span class="line"><span class="cl">mkdir -p <span class="nv">$WORK_DIR</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$WORK_DIR</span>
</span></span></code></pre></div><p>然后下载所有需要的源，它们是：<a href="https://github.com/ventanamicro/qemu/tree/dev-upstream">qemu</a>、<a href="https://github.com/ventanamicro/opensbi/tree/dev-upstream">opensbi</a>、<a href="https://github.com/ventanamicro/edk2/tree/dev-upstream">edk2</a>、<a href="https://github.com/ventanamicro/edk2-platforms/tree/dev-upstream">edk2-platforms</a>、<a href="https://github.com/ventanamicro/linux/tree/dev-upstream">linux</a>。</p>
<p>下载地址更换成了加速镜像源，原来地址下载太慢，容易中断。下载地址更换成了加速镜像源，原来地址下载太慢，容易中断。有两个项目包含子模块，下载容易出错，所以<code>--depth=1</code>舍弃了多余的提交记录。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">git clone --branch dev-upstream  https://hub.fastgit.xyz/ventanamicro/qemu.git qemu
</span></span><span class="line"><span class="cl">git clone --branch dev-upstream  https://hub.fastgit.xyz/ventanamicro/opensbi.git opensbi
</span></span><span class="line"><span class="cl">git clone --branch dev-upstream --recurse-submodules --depth<span class="o">=</span><span class="m">1</span>  https://hub.fastgit.xyz/ventanamicro/edk2.git tianocore/edk2
</span></span><span class="line"><span class="cl">git clone --branch dev-upstream --recurse-submodules --depth<span class="o">=</span><span class="m">1</span>  https://hub.fastgit.xyz/ventanamicro/edk2-platforms.git  tianocore/edk2-platforms
</span></span><span class="line"><span class="cl">git clone --branch dev-upstream  https://hub.fastgit.xyz/ventanamicro/linux.git linux
</span></span></code></pre></div><h2 id="编译构建">编译构建</h2>
<h3 id="qemu">QEMU</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$WORK_DIR</span>/qemu
</span></span><span class="line"><span class="cl">./configure --target-list<span class="o">=</span>riscv64-softmmu
</span></span><span class="line"><span class="cl">make -j <span class="k">$(</span>nproc<span class="k">)</span>
</span></span></code></pre></div><h3 id="opensbi">OPENSBI</h3>
<blockquote>
<p>此处我们使用以<code>riscv64-unknown-elf-</code>为前缀的版本，则表示该版本GCC工具链会使用newlib作为C运行库。原文使用<code>riscv64-linux-gnu-</code>，表示GCC工具链会使用Linux的Glibc作为C运行库。但是本人未编译成功。故后面编译工具均使用<code>riscv64-unknown-elf-</code>，与原文不同。</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$WORK_DIR</span>/opensbi
</span></span><span class="line"><span class="cl">make <span class="nv">ARCH</span><span class="o">=</span>riscv <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-elf- make <span class="nv">PLATFORM</span><span class="o">=</span>generic
</span></span></code></pre></div><h3 id="edk2-固件">EDK2 固件</h3>
<blockquote>
<p>此处原文里设置了一些环境变量在开头我们设置了，请不要重新设置，尤其不能<code>export WORKSPACE=pwd</code>，因为与源码脚本的WORKSPACE冲突。</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$WORK_DIR</span>/tianocore
</span></span><span class="line"><span class="cl"><span class="nb">source</span> edk2/edksetup.sh
</span></span><span class="line"><span class="cl">make -C edk2/BaseTools clean
</span></span><span class="line"><span class="cl">make -C edk2/BaseTools
</span></span><span class="line"><span class="cl">make -C edk2/BaseTools/Source/C
</span></span><span class="line"><span class="cl"><span class="nb">source</span> edk2/edksetup.sh BaseTools
</span></span><span class="line"><span class="cl"><span class="c1"># 原文使用 -buildtarget RELEASE。但是提示 Not supported target RELEASE</span>
</span></span><span class="line"><span class="cl">build -a RISCV64 -b DEBUG -D <span class="nv">FW_BASE_ADDRESS</span><span class="o">=</span>0x80200000 -D EDK2_PAYLOAD_OFFSET -p Platform/Qemu/RiscvVirt/RiscvVirt.dsc -t GCC5
</span></span></code></pre></div><h4 id="error">ERROR</h4>
<ol>
<li>
<p><strong>StoreCurrentConfiguration:7: no such file or directory: /home/user/riscv64-acpi/tianocore/Conf/BuildEnv.sh</strong></p>
<p>不要设置<code>export WORKSPACE=pwd</code>！！！如果所有方法都不可行，直接把路径写死<code>export CONF_PATH=$WORK_DIR/tianocore/edk2/Conf</code></p>
</li>
<li>
<p><strong>uuid/uuid.h: No such file or directory</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo apt install uuid-dev
</span></span></code></pre></div></li>
<li>
<p><strong>Not supported target RELEASE</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="c1"># 将build命令改为如下，使用DEBUG版本。</span>
</span></span><span class="line"><span class="cl">build -a RISCV64 -b DEBUG -D <span class="nv">FW_BASE_ADDRESS</span><span class="o">=</span>0x80200000 -D EDK2_PAYLOAD_OFFSET -p Platform/Qemu/RiscvVirt/RiscvVirt.dsc -t GCC5
</span></span></code></pre></div></li>
</ol>
<h3 id="linux">Linux</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$WORK_DIR</span>/linux
</span></span><span class="line"><span class="cl">make <span class="nv">ARCH</span><span class="o">=</span>riscv <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-elf- defconfig
</span></span><span class="line"><span class="cl">make <span class="nv">ARCH</span><span class="o">=</span>riscv <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-elf- -j <span class="k">$(</span>nproc<span class="k">)</span>
</span></span></code></pre></div><h3 id="rootfs">Rootfs</h3>
<p>您可以使用您选择的任何 rootfs。此示例使用 buildroot。</p>
<blockquote>
<p>此步耗时较久，与网络环境有关，如果网络不好可能按小时算。容易中断，需要重新下载。</p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$WORK_DIR</span>/
</span></span><span class="line"><span class="cl">git clone https://hub.fastgit.xyz/buildroot/buildroot.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$WORK_DIR</span>/buildroot
</span></span><span class="line"><span class="cl">make qemu_riscv64_virt_defconfig
</span></span><span class="line"><span class="cl">make rootfs-cpio
</span></span></code></pre></div><h2 id="创建-efi-分区并复制文件">创建 EFI 分区并复制文件</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fallocate -l 512M efi.img
</span></span><span class="line"><span class="cl">sgdisk -n 1:34: -t 1:EF00 <span class="nv">$WORK_DIR</span>/efi.img
</span></span><span class="line"><span class="cl">sudo losetup -fP <span class="nv">$WORK_DIR</span>/efi.img
</span></span><span class="line"><span class="cl"><span class="nv">loopdev</span><span class="o">=</span><span class="sb">`</span>losetup -j <span class="nv">$WORK_DIR</span>/efi.img <span class="p">|</span> awk -F: <span class="s1">&#39;{print $1}&#39;</span><span class="sb">`</span>
</span></span><span class="line"><span class="cl"><span class="nv">efi_part</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$loopdev</span><span class="s2">&#34;</span>p1
</span></span><span class="line"><span class="cl">sudo mkfs.msdos <span class="nv">$efi_part</span>
</span></span><span class="line"><span class="cl">mkdir -p /tmp/mnt
</span></span><span class="line"><span class="cl">sudo mount <span class="nv">$efi_part</span> /tmp/mnt/
</span></span><span class="line"><span class="cl">sudo cp <span class="nv">$WORK_DIR</span>/linux/arch/riscv/boot/Image /tmp/mnt/
</span></span><span class="line"><span class="cl">sudo umount /tmp/mnt
</span></span><span class="line"><span class="cl">sudo losetup -D <span class="nv">$loopdev</span>
</span></span></code></pre></div><h2 id="运行">运行</h2>
<h3 id="使用-virtio-blk-磁盘">使用 virtio-blk 磁盘</h3>
<blockquote>
<p>原文参数<code>-drive file=$WORK_DIR/buildroot/output/images/rootfs.ext2,format=raw,id=hd0</code>需要更改如下。因为在编译 Rootfs 时的命令是<code>make rootfs-cpio</code>所以生成的是<code>rootfs.cpio</code>。无法找到<code>rootfs.ext2</code></p>
</blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nv">$WORK_DIR</span>/qemu/build/qemu-system-riscv64 -nographic <span class="se">\
</span></span></span><span class="line"><span class="cl">-machine virt,aclint<span class="o">=</span>on,aia<span class="o">=</span>aplic-imsic,acpi<span class="o">=</span>on -cpu rv64,sscofpmf<span class="o">=</span><span class="nb">true</span> -smp <span class="m">8</span>  -m 2G  <span class="se">\
</span></span></span><span class="line"><span class="cl">-bios <span class="nv">$WORK_DIR</span>/opensbi/build/platform/generic/firmware/fw_jump.elf <span class="se">\
</span></span></span><span class="line"><span class="cl">-kernel <span class="nv">$WORK_DIR</span>/tianocore/Build/RiscvVirt/DEBUG_GCC5/FV/RISCVVIRT.fd  <span class="se">\
</span></span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span><span class="nv">$WORK_DIR</span>/buildroot/output/images/rootfs.cpio,format<span class="o">=</span>raw,id<span class="o">=</span>hd0 <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-blk-device,drive<span class="o">=</span>hd0 <span class="se">\
</span></span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span><span class="nv">$WORK_DIR</span>/efi.img,format<span class="o">=</span>raw,id<span class="o">=</span>hd1 <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-blk-device,drive<span class="o">=</span>hd1 <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-net-device,netdev<span class="o">=</span>usernet <span class="se">\
</span></span></span><span class="line"><span class="cl">-netdev user,id<span class="o">=</span>usernet,hostfwd<span class="o">=</span>tcp::9990-:22
</span></span></code></pre></div><h4 id="error-1">ERROR</h4>
<ol>
<li>
<p>无法找到<code>rootfs.ext2</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="c1"># 因为在编译 Rootfs 时的命令是 make rootfs-cpio 所以生成的是 rootfs.cpio</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 原文参数</span>
</span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span><span class="nv">$WORK_DIR</span>/buildroot/output/images/rootfs.ext2,format<span class="o">=</span>raw,id<span class="o">=</span>hd0 <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="c1"># 修改为</span>
</span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span><span class="nv">$WORK_DIR</span>/buildroot/output/images/rootfs.cpio,format<span class="o">=</span>raw,id<span class="o">=</span>hd0 <span class="se">\
</span></span></span></code></pre></div></li>
<li>
<p>无法找到<code>RISCVVIRT.fd</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="c1"># 因为编译 EDK2 固件时，参数是-b DEBUG 版本，原文是 RELEASE 版本，这两个版本路径不一样，所以找不到</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 原文参数</span>
</span></span><span class="line"><span class="cl">-kernel <span class="nv">$WORK_DIR</span>/tianocore/Build/RiscvVirt/RELEASE_GCC5/FV/RISCVVIRT.fd  <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="c1"># 修改为</span>
</span></span><span class="line"><span class="cl">-kernel <span class="nv">$WORK_DIR</span>/tianocore/Build/RiscvVirt/DEBUG_GCC5/FV/RISCVVIRT.fd  <span class="se">\
</span></span></span></code></pre></div></li>
</ol>
<p>At EFI Shell:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">Shell&gt; fs0:<span class="se">\I</span>mage <span class="nv">root</span><span class="o">=</span>/dev/vdb <span class="nv">console</span><span class="o">=</span>ttyS0 rootwait earlycon
</span></span></code></pre></div><p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220713153915.bmp">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220713153915.bmp" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220713153932.bmp">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220713153932.bmp" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="使用-virtio-scsi-磁盘">使用 virtio-scsi 磁盘</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nv">$WORK_DIR</span>/qemu/build/qemu-system-riscv64 -nographic <span class="se">\
</span></span></span><span class="line"><span class="cl">-machine virt,aclint<span class="o">=</span>on,aia<span class="o">=</span>aplic-imsic,acpi<span class="o">=</span>on -cpu rv64,ssofpmf<span class="o">=</span><span class="nb">true</span> -smp <span class="m">8</span>  -m 2G <span class="se">\
</span></span></span><span class="line"><span class="cl">-bios <span class="nv">$WORK_DIR</span>/opensbi/build/platform/generic/firmware/fw_jump.elf <span class="se">\
</span></span></span><span class="line"><span class="cl">-kernel <span class="nv">$WORK_DIR</span>/tianocore/Build/RiscvVirt/DEBUG_GCC5/FV/RISCVVIRT.fd  <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-scsi-pci,id<span class="o">=</span>scsi0,num_queues<span class="o">=</span><span class="m">4</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-device scsi-hd,drive<span class="o">=</span>drive0,bus<span class="o">=</span>scsi0.0,channel<span class="o">=</span>0,scsi-id<span class="o">=</span>0,lun<span class="o">=</span><span class="m">0</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span><span class="nv">$WORK_DIR</span>/buildroot/output/images/rootfs.cpio,format<span class="o">=</span>raw,if<span class="o">=</span>none,id<span class="o">=</span>drive0 <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-scsi-pci,id<span class="o">=</span>scsi1,num_queues<span class="o">=</span><span class="m">4</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-device scsi-hd,drive<span class="o">=</span>drive1,bus<span class="o">=</span>scsi0.0,channel<span class="o">=</span>0,scsi-id<span class="o">=</span>1,lun<span class="o">=</span><span class="m">0</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span><span class="nv">$WORK_DIR</span>/efi.img,format<span class="o">=</span>raw,if<span class="o">=</span>none,id<span class="o">=</span>drive1 <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-net-device,netdev<span class="o">=</span>usernet <span class="se">\
</span></span></span><span class="line"><span class="cl">-netdev user,id<span class="o">=</span>usernet,hostfwd<span class="o">=</span>tcp::9990-:22
</span></span></code></pre></div><p>At EFI Shell:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">Shell&gt; fs0:<span class="se">\I</span>mage <span class="nv">root</span><span class="o">=</span>/dev/sda <span class="nv">console</span><span class="o">=</span>ttyS0 rootwait earlycon
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>CSAPP-LAB-Cache Lab</title>
      <link>https://lifeislife.cn/posts/csapp-lab-cache-lab/</link>
      <pubDate>Mon, 11 Jul 2022 09:55:39 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/csapp-lab-cache-lab/</guid>
      <description>&lt;h2 id=&#34;预备知识&#34;&gt;预备知识&lt;/h2&gt;
&lt;p&gt;开始这个实验前，需要学习《CSAPP 第六章-存储器层次结构》的相关内容，与缓存相关的内容，我也做了相关的&lt;a href=&#34;https://dunky-z.github.io/2022/07/10/CPU-Cache%E9%AB%98%E9%80%9F%E7%BC%93%E5%AD%98/&#34;&gt;CPU Cache 高速缓存学习记录&lt;/a&gt;可以参考。&lt;/p&gt;
&lt;p&gt;实验相关的文件可以从&lt;a href=&#34;http://csapp.cs.cmu.edu/3e/labs.html&#34;&gt;CS:APP3e, Bryant and O&amp;rsquo;Hallaron&lt;/a&gt;下载。&lt;/p&gt;
&lt;p&gt;其中，&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;README：介绍实验目的和实验要求，以及实验的相关文件。需要注意的是，必须在 64-bit x86-64 system 上运行实验。需要安装 Valgrind 工具。&lt;/li&gt;
&lt;li&gt;Writeup：实验指导。&lt;/li&gt;
&lt;li&gt;Release Notes：版本发布信息。&lt;/li&gt;
&lt;li&gt;Self-Study Handout：&lt;strong&gt;需要下载的压缩包&lt;/strong&gt;，里面包含了待修改的源码文件等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下载 Self-Study Handout 并解压，得到如下文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── cachelab.c    &lt;span class=&#34;c1&#34;&gt;# 一些辅助函数，如打印输出等，不需要修改&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── cachelab.h    &lt;span class=&#34;c1&#34;&gt;# 同上&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── csim.c        &lt;span class=&#34;c1&#34;&gt;# 需要完善的主文件，需要在这里模拟Cache&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── csim-ref      &lt;span class=&#34;c1&#34;&gt;# 已经编译好的程序，我们模拟的Cache需要与这个程序运行的结果保持一致&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── driver.py     &lt;span class=&#34;c1&#34;&gt;# 驱动程序，运行 test-csim 和 test-trans&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Makefile      &lt;span class=&#34;c1&#34;&gt;# 用来编译csim程序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── README        &lt;span class=&#34;c1&#34;&gt;# &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── test-csim     &lt;span class=&#34;c1&#34;&gt;# 测试缓存模拟器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── test-trans.c  &lt;span class=&#34;c1&#34;&gt;# 测试转置功能&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── tracegen.c    &lt;span class=&#34;c1&#34;&gt;# test-trans 辅助程序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── traces        &lt;span class=&#34;c1&#34;&gt;# test-csim.c 使用的跟踪文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── dave.trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── long.trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── trans.trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── yi2.trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── yi.trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── trans.c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220711145159.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220711145159.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;part-a--writing-a-cache-simulator&#34;&gt;Part A —— Writing A Cache Simulator&lt;/h2&gt;
&lt;p&gt;在 Part A，我们将在 &lt;code&gt;csim.c&lt;/code&gt; 中编写一个缓存模拟器，它将 &lt;code&gt;valgrind&lt;/code&gt; 内存跟踪作为输入，在此跟踪上模拟高速缓存的命中/未命中行为，并输出命中、未命中和驱逐的总数。&lt;/p&gt;
&lt;p&gt;这里的输入由&lt;code&gt;valgrind&lt;/code&gt;通过以下命令生成的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;valgrind --log-fd&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; --tool&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;lackey -v --trace-mem&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;yes ls -l
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;--log-fd=1&lt;/code&gt;表示将输出输出到标准输出；
&lt;code&gt;--tool=lackey&lt;/code&gt;：Lackey 是一个简单的 Valgrind 工具，可进行各种基本程序测量；
&lt;code&gt;--trace-mem=yes&lt;/code&gt;：Lackey 的一个参数，启用后，Lackey 会打印程序几乎所有内存访问的大小和地址；
&lt;code&gt;ls -l&lt;/code&gt;：是一个简单的程序，可以查看当前目录下的文件列表。
也就是检测&lt;code&gt;ls -l&lt;/code&gt;程序在运行时访问内存的情况。&lt;/p&gt;
&lt;p&gt;执行结果像下面的形式：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# [space]operation address,size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I  0400639c,4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; L 1ffeffec00,8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I  040063a0,2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; S 1ffeffea50,8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I  040063a2,4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; L 1ffeffebf0,8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I  040063a6,3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I  040063a9,3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; L 1ffeffebf8,4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I  040063ac,7
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;操作字段表示内存访问的类型：&lt;code&gt;I&lt;/code&gt;表示指令加载，&lt;code&gt;L&lt;/code&gt;表示数据加载，&lt;code&gt;S&lt;/code&gt;表示数据存储，&lt;code&gt;M&lt;/code&gt;表示数据修改（即，数据加载后跟数据存储） ）。每个&lt;code&gt;I&lt;/code&gt;之前都没有空格。每个&lt;code&gt;M&lt;/code&gt;、&lt;code&gt;L&lt;/code&gt;和&lt;code&gt;S&lt;/code&gt;之前总是有一个空格。地址字段指定一个 &lt;code&gt;64&lt;/code&gt; 位的十六进制内存地址。 &lt;code&gt;size&lt;/code&gt; 字段指定操作访问的字节数。&lt;/p&gt;
&lt;p&gt;了解这些基础后，&lt;strong&gt;我们最主要的是要明确，我们需要实现一个什么样的程序，这个程序具体有哪些参数，怎么执行的&lt;/strong&gt;。&lt;code&gt;csim-ref&lt;/code&gt;是已经完成的可执行文件，它的用法是&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./csim-ref &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;-hv&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; -s &amp;lt;s&amp;gt; -E &amp;lt;E&amp;gt; -b &amp;lt;b&amp;gt; -t &amp;lt;tracefile&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-h&lt;/code&gt;：打印帮助信息；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v&lt;/code&gt;：显示详细信息，如是 I，L 还是 M；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s &amp;lt;s&amp;gt;&lt;/code&gt;：组索引位数（$S=2^{s}$组个数）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-E &amp;lt;E&amp;gt;&lt;/code&gt;：关联性（每组的行数）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-b &amp;lt;b&amp;gt;&lt;/code&gt;：块位数（$B=2^{b}$ 是块大小）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t &amp;lt;tracefile&amp;gt;&lt;/code&gt;：valgrind 生成的文件；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./csim-ref -s &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; -E &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -b &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; -t traces/yi.trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hits:4 misses:5 evictions:3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果显示详细信息可以执行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./csim-ref -v -s &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; -E &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; -b &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; -t traces/yi.trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;L 10,1 miss
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;M 20,1 miss hit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;L 22,1 hit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;S 18,1 hit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;L 110,1 miss eviction
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;L 210,1 miss eviction
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;M 12,1 miss eviction hit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hits:4 misses:5 evictions:3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们的目的就是要完善&lt;code&gt;csim.c&lt;/code&gt;，使其能够使用上面相同的参数，得到与&lt;code&gt;csim-ref&lt;/code&gt;相同的结果。
&lt;a href=&#34;http://www.cs.cmu.edu/afs/cs/academic/class/15213-f15/www/recitations/rec07.pdf&#34;&gt;Cache Lab Implementa/on and Blocking&lt;/a&gt;这份 PPT 里有一些实验指导，可以参考。
首先需要解决的就是如何处理输入的参数，我们可以使用 PPT 里提到的&lt;code&gt;getopt&lt;/code&gt;库来解决。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdbool.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;cachelab.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;getopt.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 组个数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 组占的位数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;E&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hits&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;misses&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;evictions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_CacheLine&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_CacheLine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_CacheLine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_Cache&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Cache&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;parse_option&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;option&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;getopt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;s:E:b:t:&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;s&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;atoi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// 传入的参数为占用的bit，需要转换为10进制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;S&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;E&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;E&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;atoi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;B&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;atoi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;t&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;strcpy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;initialize_cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tail&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tail&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prev&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/*!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @breif Add a new CacheLine to the Cache first line
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param nodeToDel CacheLine to be deleted
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param curLru  Current Cache
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;insert_first_line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Cache&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prev&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prev&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;evict&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodeToDel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Cache&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;nodeToDel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prev&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodeToDel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;nodeToDel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prev&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodeToDel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;maskSet&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 取出组索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targetSet&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;maskSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 取出标记
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targetTag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Cache&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;targetSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 查找是否存与当前标记位相同的缓存行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cur&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;found&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cur&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cur&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targetTag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;found&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;cur&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cur&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;found&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;hits&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;evict&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cur&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;insert_first_line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cur&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;gt; hit!, set: %d &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targetSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newNode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CacheLine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;newNode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tag&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targetTag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;E&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 如果缓存已满，则删除最后一个缓存行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;evict&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tail&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prev&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;insert_first_line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;evictions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;misses&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;gt; evic &amp;amp;&amp;amp; miss set:%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targetSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;misses&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;insert_first_line&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;newNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curLru&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;gt; miss %d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targetSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;cache_simulate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 分配并初始化S组缓存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;initialize_cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FILE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fopen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;fscanf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34; %c %x,%d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%c, %x %d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;L&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;M&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;sc&#34;&gt;&amp;#39;S&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileName&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;parse_option&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cache_simulate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fileName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;printSummary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hits&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;misses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;evictions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="预备知识">预备知识</h2>
<p>开始这个实验前，需要学习《CSAPP 第六章-存储器层次结构》的相关内容，与缓存相关的内容，我也做了相关的<a href="https://dunky-z.github.io/2022/07/10/CPU-Cache%E9%AB%98%E9%80%9F%E7%BC%93%E5%AD%98/">CPU Cache 高速缓存学习记录</a>可以参考。</p>
<p>实验相关的文件可以从<a href="http://csapp.cs.cmu.edu/3e/labs.html">CS:APP3e, Bryant and O&rsquo;Hallaron</a>下载。</p>
<p>其中，</p>
<ul>
<li>README：介绍实验目的和实验要求，以及实验的相关文件。需要注意的是，必须在 64-bit x86-64 system 上运行实验。需要安装 Valgrind 工具。</li>
<li>Writeup：实验指导。</li>
<li>Release Notes：版本发布信息。</li>
<li>Self-Study Handout：<strong>需要下载的压缩包</strong>，里面包含了待修改的源码文件等。</li>
</ul>
<p>下载 Self-Study Handout 并解压，得到如下文件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">├── cachelab.c    <span class="c1"># 一些辅助函数，如打印输出等，不需要修改</span>
</span></span><span class="line"><span class="cl">├── cachelab.h    <span class="c1"># 同上</span>
</span></span><span class="line"><span class="cl">├── csim.c        <span class="c1"># 需要完善的主文件，需要在这里模拟Cache</span>
</span></span><span class="line"><span class="cl">├── csim-ref      <span class="c1"># 已经编译好的程序，我们模拟的Cache需要与这个程序运行的结果保持一致</span>
</span></span><span class="line"><span class="cl">├── driver.py     <span class="c1"># 驱动程序，运行 test-csim 和 test-trans</span>
</span></span><span class="line"><span class="cl">├── Makefile      <span class="c1"># 用来编译csim程序</span>
</span></span><span class="line"><span class="cl">├── README        <span class="c1"># </span>
</span></span><span class="line"><span class="cl">├── test-csim     <span class="c1"># 测试缓存模拟器</span>
</span></span><span class="line"><span class="cl">├── test-trans.c  <span class="c1"># 测试转置功能</span>
</span></span><span class="line"><span class="cl">├── tracegen.c    <span class="c1"># test-trans 辅助程序</span>
</span></span><span class="line"><span class="cl">├── traces        <span class="c1"># test-csim.c 使用的跟踪文件</span>
</span></span><span class="line"><span class="cl">│   ├── dave.trace
</span></span><span class="line"><span class="cl">│   ├── long.trace
</span></span><span class="line"><span class="cl">│   ├── trans.trace
</span></span><span class="line"><span class="cl">│   ├── yi2.trace
</span></span><span class="line"><span class="cl">│   └── yi.trace
</span></span><span class="line"><span class="cl">└── trans.c
</span></span></code></pre></div><p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220711145159.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220711145159.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="part-a--writing-a-cache-simulator">Part A —— Writing A Cache Simulator</h2>
<p>在 Part A，我们将在 <code>csim.c</code> 中编写一个缓存模拟器，它将 <code>valgrind</code> 内存跟踪作为输入，在此跟踪上模拟高速缓存的命中/未命中行为，并输出命中、未命中和驱逐的总数。</p>
<p>这里的输入由<code>valgrind</code>通过以下命令生成的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">valgrind --log-fd<span class="o">=</span><span class="m">1</span> --tool<span class="o">=</span>lackey -v --trace-mem<span class="o">=</span>yes ls -l
</span></span></code></pre></div><p><code>--log-fd=1</code>表示将输出输出到标准输出；
<code>--tool=lackey</code>：Lackey 是一个简单的 Valgrind 工具，可进行各种基本程序测量；
<code>--trace-mem=yes</code>：Lackey 的一个参数，启用后，Lackey 会打印程序几乎所有内存访问的大小和地址；
<code>ls -l</code>：是一个简单的程序，可以查看当前目录下的文件列表。
也就是检测<code>ls -l</code>程序在运行时访问内存的情况。</p>
<p>执行结果像下面的形式：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># [space]operation address,size</span>
</span></span><span class="line"><span class="cl">I  0400639c,4
</span></span><span class="line"><span class="cl"> L 1ffeffec00,8
</span></span><span class="line"><span class="cl">I  040063a0,2
</span></span><span class="line"><span class="cl"> S 1ffeffea50,8
</span></span><span class="line"><span class="cl">I  040063a2,4
</span></span><span class="line"><span class="cl"> L 1ffeffebf0,8
</span></span><span class="line"><span class="cl">I  040063a6,3
</span></span><span class="line"><span class="cl">I  040063a9,3
</span></span><span class="line"><span class="cl"> L 1ffeffebf8,4
</span></span><span class="line"><span class="cl">I  040063ac,7
</span></span></code></pre></div><p>操作字段表示内存访问的类型：<code>I</code>表示指令加载，<code>L</code>表示数据加载，<code>S</code>表示数据存储，<code>M</code>表示数据修改（即，数据加载后跟数据存储） ）。每个<code>I</code>之前都没有空格。每个<code>M</code>、<code>L</code>和<code>S</code>之前总是有一个空格。地址字段指定一个 <code>64</code> 位的十六进制内存地址。 <code>size</code> 字段指定操作访问的字节数。</p>
<p>了解这些基础后，<strong>我们最主要的是要明确，我们需要实现一个什么样的程序，这个程序具体有哪些参数，怎么执行的</strong>。<code>csim-ref</code>是已经完成的可执行文件，它的用法是</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./csim-ref <span class="o">[</span>-hv<span class="o">]</span> -s &lt;s&gt; -E &lt;E&gt; -b &lt;b&gt; -t &lt;tracefile&gt;
</span></span></code></pre></div><ul>
<li><code>-h</code>：打印帮助信息；</li>
<li><code>-v</code>：显示详细信息，如是 I，L 还是 M；</li>
<li><code>-s &lt;s&gt;</code>：组索引位数（$S=2^{s}$组个数）；</li>
<li><code>-E &lt;E&gt;</code>：关联性（每组的行数）；</li>
<li><code>-b &lt;b&gt;</code>：块位数（$B=2^{b}$ 是块大小）；</li>
<li><code>-t &lt;tracefile&gt;</code>：valgrind 生成的文件；</li>
</ul>
<p>如：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./csim-ref -s <span class="m">4</span> -E <span class="m">1</span> -b <span class="m">4</span> -t traces/yi.trace
</span></span><span class="line"><span class="cl">hits:4 misses:5 evictions:3
</span></span></code></pre></div><p>如果显示详细信息可以执行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">./csim-ref -v -s <span class="m">4</span> -E <span class="m">1</span> -b <span class="m">4</span> -t traces/yi.trace
</span></span><span class="line"><span class="cl">L 10,1 miss
</span></span><span class="line"><span class="cl">M 20,1 miss hit
</span></span><span class="line"><span class="cl">L 22,1 hit
</span></span><span class="line"><span class="cl">S 18,1 hit
</span></span><span class="line"><span class="cl">L 110,1 miss eviction
</span></span><span class="line"><span class="cl">L 210,1 miss eviction
</span></span><span class="line"><span class="cl">M 12,1 miss eviction hit
</span></span><span class="line"><span class="cl">hits:4 misses:5 evictions:3
</span></span></code></pre></div><p>我们的目的就是要完善<code>csim.c</code>，使其能够使用上面相同的参数，得到与<code>csim-ref</code>相同的结果。
<a href="http://www.cs.cmu.edu/afs/cs/academic/class/15213-f15/www/recitations/rec07.pdf">Cache Lab Implementa/on and Blocking</a>这份 PPT 里有一些实验指导，可以参考。
首先需要解决的就是如何处理输入的参数，我们可以使用 PPT 里提到的<code>getopt</code>库来解决。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdbool.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;cachelab.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;getopt.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="n">S</span><span class="p">;</span> <span class="c1">// 组个数
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="n">s</span><span class="p">;</span> <span class="c1">// 组占的位数
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="n">E</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="n">B</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="n">hits</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="n">misses</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="n">evictions</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="n">_CacheLine</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="n">tag</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">_CacheLine</span> <span class="o">*</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">_CacheLine</span> <span class="o">*</span><span class="n">prev</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">CacheLine</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="n">_Cache</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">CacheLine</span> <span class="o">*</span><span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">CacheLine</span> <span class="o">*</span><span class="n">tail</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="o">*</span><span class="n">size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">Cache</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">Cache</span> <span class="o">*</span><span class="n">cache</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">parse_option</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">fileName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">option</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">((</span><span class="n">option</span> <span class="o">=</span> <span class="nf">getopt</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="s">&#34;s:E:b:t:&#34;</span><span class="p">))</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">switch</span> <span class="p">(</span><span class="n">option</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="sc">&#39;s&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">s</span> <span class="o">=</span> <span class="nf">atoi</span><span class="p">(</span><span class="n">optarg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 传入的参数为占用的bit，需要转换为10进制
</span></span></span><span class="line"><span class="cl">            <span class="n">S</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">s</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="sc">&#39;E&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">E</span> <span class="o">=</span> <span class="nf">atoi</span><span class="p">(</span><span class="n">optarg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="sc">&#39;b&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">B</span> <span class="o">=</span> <span class="nf">atoi</span><span class="p">(</span><span class="n">optarg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="sc">&#39;t&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">            <span class="nf">strcpy</span><span class="p">(</span><span class="o">*</span><span class="n">fileName</span><span class="p">,</span> <span class="n">optarg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">initialize_cache</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cache</span> <span class="o">=</span> <span class="nf">malloc</span><span class="p">(</span><span class="n">S</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">cache</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">S</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">cache</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">head</span> <span class="o">=</span> <span class="nf">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">CacheLine</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="n">cache</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">tail</span> <span class="o">=</span> <span class="nf">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">CacheLine</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">cache</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">cache</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">tail</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">cache</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">tail</span><span class="o">-&gt;</span><span class="n">prev</span> <span class="o">=</span> <span class="n">cache</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">cache</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">)</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="nf">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">int</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="o">*</span><span class="p">(</span><span class="n">cache</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">size</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/*!
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @breif Add a new CacheLine to the Cache first line
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param nodeToDel CacheLine to be deleted
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param curLru  Current Cache
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">insert_first_line</span><span class="p">(</span><span class="n">CacheLine</span> <span class="o">*</span><span class="n">node</span><span class="p">,</span> <span class="n">Cache</span> <span class="o">*</span><span class="n">curLru</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">node</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">curLru</span><span class="o">-&gt;</span><span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">node</span><span class="o">-&gt;</span><span class="n">prev</span> <span class="o">=</span> <span class="n">curLru</span><span class="o">-&gt;</span><span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">curLru</span><span class="o">-&gt;</span><span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">prev</span> <span class="o">=</span> <span class="n">node</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">curLru</span><span class="o">-&gt;</span><span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">node</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="p">(</span><span class="n">curLru</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">)</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">curLru</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">evict</span><span class="p">(</span><span class="n">CacheLine</span> <span class="o">*</span><span class="n">nodeToDel</span><span class="p">,</span> <span class="n">Cache</span> <span class="o">*</span><span class="n">curLru</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">nodeToDel</span><span class="o">-&gt;</span><span class="n">next</span><span class="o">-&gt;</span><span class="n">prev</span> <span class="o">=</span> <span class="n">nodeToDel</span><span class="o">-&gt;</span><span class="n">prev</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">nodeToDel</span><span class="o">-&gt;</span><span class="n">prev</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">nodeToDel</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="p">(</span><span class="n">curLru</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">)</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="n">curLru</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">update</span><span class="p">(</span><span class="kt">unsigned</span> <span class="n">address</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">mask</span> <span class="o">=</span> <span class="mh">0xFFFFFFFF</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">maskSet</span> <span class="o">=</span> <span class="n">mask</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="mi">32</span> <span class="o">-</span> <span class="n">s</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 取出组索引
</span></span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">targetSet</span> <span class="o">=</span> <span class="p">((</span><span class="n">maskSet</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">address</span> <span class="o">&gt;&gt;</span> <span class="n">B</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 取出标记
</span></span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">targetTag</span> <span class="o">=</span> <span class="n">address</span> <span class="o">&gt;&gt;</span> <span class="p">(</span><span class="n">s</span> <span class="o">+</span> <span class="n">B</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">Cache</span> <span class="n">curLru</span> <span class="o">=</span> <span class="n">cache</span><span class="p">[</span><span class="n">targetSet</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 查找是否存与当前标记位相同的缓存行
</span></span></span><span class="line"><span class="cl">    <span class="n">CacheLine</span> <span class="o">*</span><span class="n">cur</span> <span class="o">=</span> <span class="n">curLru</span><span class="p">.</span><span class="n">head</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">found</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">cur</span> <span class="o">!=</span> <span class="n">curLru</span><span class="p">.</span><span class="n">tail</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">cur</span><span class="o">-&gt;</span><span class="n">tag</span> <span class="o">==</span> <span class="n">targetTag</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">found</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">cur</span> <span class="o">=</span> <span class="n">cur</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">found</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">hits</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="nf">evict</span><span class="p">(</span><span class="n">cur</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">curLru</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">insert_first_line</span><span class="p">(</span><span class="n">cur</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">curLru</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;&gt; hit!, set: %d </span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">targetSet</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">CacheLine</span> <span class="o">*</span><span class="n">newNode</span> <span class="o">=</span> <span class="nf">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">CacheLine</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="n">newNode</span><span class="o">-&gt;</span><span class="n">tag</span> <span class="o">=</span> <span class="n">targetTag</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="p">(</span><span class="n">curLru</span><span class="p">.</span><span class="n">size</span><span class="p">)</span> <span class="o">==</span> <span class="n">E</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 如果缓存已满，则删除最后一个缓存行
</span></span></span><span class="line"><span class="cl">            <span class="nf">evict</span><span class="p">(</span><span class="n">curLru</span><span class="p">.</span><span class="n">tail</span><span class="o">-&gt;</span><span class="n">prev</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">curLru</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nf">insert_first_line</span><span class="p">(</span><span class="n">newNode</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">curLru</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">evictions</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">misses</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;&gt; evic &amp;&amp; miss set:%d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">targetSet</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">misses</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nf">insert_first_line</span><span class="p">(</span><span class="n">newNode</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">curLru</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;&gt; miss %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">targetSet</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">cache_simulate</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">fileName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 分配并初始化S组缓存
</span></span></span><span class="line"><span class="cl">    <span class="nf">initialize_cache</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">FILE</span> <span class="o">*</span><span class="n">file</span> <span class="o">=</span> <span class="nf">fopen</span><span class="p">(</span><span class="n">fileName</span><span class="p">,</span> <span class="s">&#34;r&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="n">op</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">address</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="nf">fscanf</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="s">&#34; %c %x,%d&#34;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">op</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">address</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">size</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%c, %x %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">op</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">switch</span> <span class="p">(</span><span class="n">op</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="sc">&#39;L&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">            <span class="nf">update</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="sc">&#39;M&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">            <span class="nf">update</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">case</span> <span class="sc">&#39;S&#39;</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">            <span class="nf">update</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="o">*</span><span class="n">fileName</span> <span class="o">=</span> <span class="nf">malloc</span><span class="p">(</span><span class="mi">100</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">char</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">parse_option</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fileName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">cache_simulate</span><span class="p">(</span><span class="n">fileName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printSummary</span><span class="p">(</span><span class="n">hits</span><span class="p">,</span> <span class="n">misses</span><span class="p">,</span> <span class="n">evictions</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-watch 周期执行命令</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-watch%E5%91%A8%E6%9C%9F%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4/</link>
      <pubDate>Thu, 09 Jun 2022 22:50:54 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-watch%E5%91%A8%E6%9C%9F%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4/</guid>
      <description>&lt;h2 id=&#34;功能&#34;&gt;功能&lt;/h2&gt;
&lt;p&gt;watch 命令的功能如其名，可以监视命令的执行结果。它实现的原理就是每隔一段时间执行一次命令，然后显示结果。他的用途很广，具体怎么用就靠想象力了。&lt;/p&gt;
&lt;h2 id=&#34;命令参数&#34;&gt;命令参数&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-n # 或--interval  watch默认每2秒运行一下程序，可以用-n或-interval来指定间隔的时间。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-d # 或--differences  用-d或--differences 选项watch 会高亮显示变化的区域。 而-d=cumulative选项会把变动过的地方(不管最近的那次有没有变动)都高亮显示出来。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-t # 或-no-title  会关闭watch命令在顶部的时间间隔,命令，当前时间的输出。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-h # 或--help # 查看帮助文档
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;实例&#34;&gt;实例&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;watch -d &amp;#39;ls -l | grep tmp&amp;#39;       # 监测当前目录中 scf&amp;#39; 的文件的变化
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="功能">功能</h2>
<p>watch 命令的功能如其名，可以监视命令的执行结果。它实现的原理就是每隔一段时间执行一次命令，然后显示结果。他的用途很广，具体怎么用就靠想象力了。</p>
<h2 id="命令参数">命令参数</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">-n # 或--interval  watch默认每2秒运行一下程序，可以用-n或-interval来指定间隔的时间。
</span></span><span class="line"><span class="cl">-d # 或--differences  用-d或--differences 选项watch 会高亮显示变化的区域。 而-d=cumulative选项会把变动过的地方(不管最近的那次有没有变动)都高亮显示出来。
</span></span><span class="line"><span class="cl">-t # 或-no-title  会关闭watch命令在顶部的时间间隔,命令，当前时间的输出。
</span></span><span class="line"><span class="cl">-h # 或--help # 查看帮助文档
</span></span></code></pre></div><h2 id="实例">实例</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">watch -d &#39;ls -l | grep tmp&#39;       # 监测当前目录中 scf&#39; 的文件的变化
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>CPU 亲和性与中断亲和性</title>
      <link>https://lifeislife.cn/posts/cpu%E4%BA%B2%E5%92%8C%E6%80%A7%E4%B8%8E%E4%B8%AD%E6%96%AD%E4%BA%B2%E5%92%8C%E6%80%A7/</link>
      <pubDate>Mon, 23 May 2022 22:38:14 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/cpu%E4%BA%B2%E5%92%8C%E6%80%A7%E4%B8%8E%E4%B8%AD%E6%96%AD%E4%BA%B2%E5%92%8C%E6%80%A7/</guid>
      <description>&lt;h2 id=&#34;预备知识&#34;&gt;预备知识&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/HwDqCk8vtMdSEVSCLHAsbg&#34;&gt;超线程技术 (Hyper-Threading)&lt;/a&gt;：就是利用特殊的硬件指令，把两个逻辑内核 (CPU core) 模拟成两个物理芯片，让单个处理器都能使用线程级并行计算，进而兼容多线程操作系统和软件，减少了 CPU 的闲置时间，提高的 CPU 的运行效率。&lt;/p&gt;
&lt;p&gt;我们常听到的双核四线程/四核八线程指的就是支持超线程技术的CPU.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;物理 CPU&lt;/strong&gt;：机器上安装的实际 CPU, 比如说你的主板上安装了一个 8 核 CPU，那么物理 CPU 个数就是 1 个，所以物理 CPU 个数就是主板上安装的 CPU 个数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;逻辑 CPU&lt;/strong&gt;：一般情况，我们认为一颗 CPU 可以有多核，加上 Intel 的超线程技术 (HT), 可以在逻辑上再分一倍数量的 CPU core 出来；&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;逻辑CPU数量 = 物理CPU数量 x CPU cores x 2(如果支持并开启HT) //前提是CPU的型号一致，如果不一致只能一个一个的加起来，不用直接乘以物理CPU数量
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;//比如你的电脑安装了一块4核CPU，并且支持且开启了超线程（HT）技术，那么逻辑CPU数量 = 1 × 4 × 2 = 8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Linux 下查看 CPU 相关信息&lt;/strong&gt;, CPU 的信息主要都在&lt;code&gt;/proc/cupinfo&lt;/code&gt;中。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 查看物理CPU个数
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat /proc/cpuinfo|grep &amp;#34;physical id&amp;#34;|sort -u|wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;32
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 查看每个物理CPU中core的个数(即核数)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat /proc/cpuinfo|grep &amp;#34;cpu cores&amp;#34;|uniq
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 或者
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜    cat /proc/cpuinfo | grep &amp;#39;process&amp;#39; | sort | uniq | wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 查看逻辑CPU的个数
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat /proc/cpuinfo|grep &amp;#34;processor&amp;#34;|wc -l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;32
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 查看CPU的名称型号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat /proc/cpuinfo|grep &amp;#34;name&amp;#34;|cut -f2 -d:|uniq
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Intel Xeon Processor (Skylake, IBRS)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Linux 查看某个进程运行在哪个逻辑 CPU 上&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ps -eo pid,args,psr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pid&lt;/code&gt;：进程 ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;args&lt;/code&gt;：该进程执行时传入的命令行参数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;psr&lt;/code&gt;：分配给进程的逻辑 CPU&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ps -eo pid,args,psr | grep firefox
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20118 /usr/lib/firefox/firefox -n  13
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20208 /usr/lib/firefox/firefox -c   9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20266 /usr/lib/firefox/firefox -c  29
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20329 /usr/lib/firefox/firefox -c  24
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20499 /usr/lib/firefox/firefox -c   7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20565 /usr/lib/firefox/firefox -c  15
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20596 /usr/lib/firefox/firefox -c  24
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20760 /usr/lib/firefox/firefox -c  18
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;22110 /usr/lib/firefox/firefox -c  27
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;25857 /usr/lib/firefox/firefox -c  28
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;26347 /usr/lib/firefox/firefox -c  19
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;26899 /usr/lib/firefox/firefox -c  29
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Linux 查看线程的 TID&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TID 就是 Thread ID，他和 POSIX 中&lt;code&gt;pthread_t&lt;/code&gt;表示的线程 ID 完全不是同一个东西。&lt;/p&gt;
&lt;p&gt;Linux 中的 POSIX 线程库实现的线程其实也是一个轻量级进程 (LWP),这个 TID 就是这个线程的真实 PID.&lt;/p&gt;
&lt;p&gt;但是又不能通过&lt;code&gt;getpid()&lt;/code&gt;函数获取，Linux 中定义了&lt;code&gt;gettid()&lt;/code&gt;这个接口，但是通常都是未实现的，所以需要使用下面的方式获取 TID。&lt;/p&gt;
&lt;p&gt;使用 API 获取：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/syscall.h&amp;gt;  &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;tid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__NR_gettid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// or syscall(SYS_gettid)  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;命令行方式获取：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 3种方法(推荐第三种方法)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ps -efL | grep prog_name
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ls /proc/pid/task      //文件夹名即TID
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ps -To &amp;#39;pid,lwp,psr,cmd&amp;#39; -p PID
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;什么是-cpu-亲和性&#34;&gt;什么是 CPU 亲和性&lt;/h2&gt;
&lt;p&gt;CPU 的亲和性 (Affinity)，属于一种调度属性，可以绑定进程到指定 CPU 上。 换句话说，就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器。&lt;/p&gt;
&lt;p&gt;为何会出现这种技术？在 SMP(Symmetric Multi-Processing 对称多处理) 架构下，调度器会试图保持进程在相同的 CPU 上运行，这意味着进程通常不会在处理器之间频繁迁移，进程迁移的频率小就意味着产生的负载小。&lt;/p&gt;
&lt;p&gt;又如，每个 CPU 本身自己会有缓存，缓存着进程使用的信息，而进程可能会被操作系统调度到其他 CPU 上，如此，CPU 缓存命中率就低了，当绑定 CPU 后，程序就会一直在指定的 CPU 跑，不会由操作系统调度到其他 CPU 上，性能有一定的提高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;软亲和性&lt;/strong&gt;:  就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器，Linux 内核进程调度器天生就具有被称为 软 CPU 亲和性（affinity）的特性，这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的，因为进程迁移的频率小就意味着产生的负载小。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;硬亲和性&lt;/strong&gt;：简单来说就是利用 Linux 内核提供给用户的 API，强行将进程或者线程绑定到某一个指定的 CPU 核运行。&lt;/p&gt;
&lt;p&gt;CPU affinity 使用位掩码 (bitmask) 表示，每一位都表示一个 CPU, 置 1 表示&amp;quot;绑定&amp;quot;。最低位表示第一个逻辑 CPU, 最高位表示最后一个逻辑 CPU。&lt;/p&gt;
&lt;p&gt;CPU affinity 典型的表示方法是使用 16 进制，具体如下。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0b00000000000000000000000000000001
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;= 0x00000001
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;表示 processor #0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0b00000000000000000000000001010101
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;= 0x00000055
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;表示 processors #0, #2, #4, #6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0b11111111111111111111111111111111
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;= 0xFFFFFFFF
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;表示所有 processors (#0 through #31)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用taskset命令设置-cpu-亲和性&#34;&gt;使用&lt;code&gt;taskset&lt;/code&gt;命令设置 CPU 亲和性&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;命令行形式&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;taskset [options] mask command [arg]...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;taskset [options] -p [mask] pid
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;参数解析&lt;/strong&gt;
[OPTIONS]taskset 的可选参数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-a, --all-tasks&lt;/code&gt; (旧版本中没有这个选项)
这个选项涉及到了linux中TID的概念,他会将一个进程中所有的TID都执行一次CPU亲和性设置.
TID 就是 Thread ID，他和 POSIX 中 pthread_t 表示的线程 ID 完全不是同一个东西。
Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),这个TID就是这个线程的真实PID.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-p, --pid&lt;/code&gt;
操作已存在的PID,而不是加载一个新的程序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-c, --cpu-list&lt;/code&gt;
声明CPU的亲和力使用数字表示而不是用位掩码表示. 例如 0,5,7,9-11.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-h, --help&lt;/code&gt;
显示帮助信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-V, --version&lt;/code&gt;
显示版本信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;mask&lt;/code&gt; : cpu 亲和性，当没有&lt;code&gt;-c&lt;/code&gt;选项时，其值前无论有没有&lt;code&gt;0x&lt;/code&gt;标记都是 16 进制的，当有&lt;code&gt;-c&lt;/code&gt;选项时，其值是十进制的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;command&lt;/code&gt; : 命令或者可执行程序&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;pid&lt;/code&gt; : 进程 ID，可以通过&lt;code&gt;ps/top/pidof&lt;/code&gt;等命令获取&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;[arg]&lt;/code&gt; command 的参数&lt;/p&gt;
&lt;h3 id=&#34;实例&#34;&gt;实例&lt;/h3&gt;
&lt;h4 id=&#34;使用指定的-cpu-亲和性运行一个新程序&#34;&gt;使用指定的 CPU 亲和性运行一个新程序&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;taskset &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;-c&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; mask &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;arg&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 举例: 使用CPU0运行ls命令显示/etc/init.d下的所有内容&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;taskset -c &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ls -al /etc/init.d/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;显示已经运行的进程的-cpu-亲和性&#34;&gt;显示已经运行的进程的 CPU 亲和性&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;taskset -p pid
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 举例:查看init进程(PID=1)的CPU亲和性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;taskset -p &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;改变已经运行进程的-cpu-亲和性&#34;&gt;改变已经运行进程的 CPU 亲和性&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;taskset -p[c] mask pid
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;举例:打开2个终端,在第一个终端运行top命令,第二个终端中
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 　　首先运行:[~]# ps -eo pid,args,psr | grep top #获取top命令的pid和其所运行的CPU号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 　　其次运行:[~]# taskset -cp 新的CPU号 pid       #更改top命令运行的CPU号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 　　最后运行:[~]# ps -eo pid,args,psr | grep top #查看是否更改成功
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps -eo pid,args,psr | grep top
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2501 nautilus-desktop             24
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2634 /usr/libexec/xdg-desktop-po  18
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2658 /usr/libexec/xdg-desktop-po  11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;23848 top                           6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ taskset -cp 10 23848
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pid 23848&amp;#39;s current affinity list: 0-31
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pid 23848&amp;#39;s new affinity list: 10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps -eo pid,args,psr | grep top
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 2501 nautilus-desktop             24
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 2634 /usr/libexec/xdg-desktop-po  18
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 2658 /usr/libexec/xdg-desktop-po  11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;23848 top                          10
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;一个用户要设定一个进程的 CPU 亲和性，如果目标进程是该用户的，则可以设置，如果是其他用户的，则会设置失败，提示 Operation not permitted.当然 root 用户没有任何限制。
任何用户都可以获取任意一个进程的 CPU 亲和性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;程序-api-实现硬亲和性&#34;&gt;程序 API 实现硬亲和性&lt;/h2&gt;
&lt;p&gt;以下实验使用的源码可以从&lt;a href=&#34;https://github.com/Dunky-Z/learning-linux/tree/main/Affinity&#34;&gt;这个仓库&lt;/a&gt;获取。&lt;/p&gt;
&lt;p&gt;以下是一些设置亲和性时会用到的宏定义及函数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define _GNU_SOURCE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sched.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;pthread.h&amp;gt; //注意&amp;lt;pthread.h&amp;gt;包含&amp;lt;sched.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* MACRO */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 对 CPU 集初始化，将其设置为空集
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_ZERO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_ZERO_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 将 CPU 加入到 CPU 集中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_SET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_SET_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 将 CPU 从 CPU 集中移除
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_CLR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_CLR_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 判断 CPU 是否在 CPU 集中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_ISSET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_ISSET_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 计算 CPU 集的大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_COUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_COUNT_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// The following macros perform logical operations on CPU sets 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Store the logical AND of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_AND&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_AND_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Store the logical OR of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_OR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_OR_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Store  the logical XOR of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_XOR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_XOR_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;srcset2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Test whether two CPU set contain exactly the same CPUs. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_EQUAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_EQUAL_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;setsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* The following macros are used to allocate and deallocate CPU sets: */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Allocate a CPU set large enough to hold CPUs in the range 0 to num_cpus-1 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CPU_ALLOC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_cpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Return the size in bytes of the CPU set that would be needed to  hold  CPUs  in the  range 0 to num_cpus-1. 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;           This macro provides the value that can be used for the setsize argument in the CPU_*_S() macros */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_ALLOC_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_cpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Free a CPU set previously allocated by CPU_ALLOC(). */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_FREE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* API */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/*该函数设置进程为 pid 的这个进程，让它运行在 mask 所设定的 CPU 上。如果 pid 的值为 0,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    *则表示指定的是当前进程，使当前进程运行在 mask 所设定的那些 CPU 上.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    *第二个参数 cpusetsize 是 mask 所指定的数的长度。通常设定为 sizeof(cpu_set_t).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    *如果当前 pid 所指定的进程此时没有运行在 mask 所指定的任意一个 CPU 上，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    *则该指定的进程会从其它 CPU 上迁移到 mask 的指定的一个 CPU 上运行.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sched_setaffinity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusetsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/*该函数获得 pid 所指示的进程的 CPU 位掩码，并将该掩码返回到 mask 所指向的结构中.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    *即获得指定 pid 当前可以运行在哪些 CPU 上.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    *同样，如果 pid 的值为 0.也表示的是当前进程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;    */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sched_getaffinity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusetsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* set CPU affinity attribute in thread attributes object */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pthread_attr_setaffinity_np&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pthread_attr_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusetsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* get CPU affinity attribute in thread attributes object */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pthread_attr_getaffinity_np&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;pthread_attr_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusetsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* set CPU affinity of a thread */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pthread_setaffinity_np&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pthread_t&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;thread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusetsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* get CPU affinity of a thread */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pthread_getaffinity_np&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;pthread_t&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;thread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusetsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;程序中会使用&lt;code&gt;syscall&lt;/code&gt;来获取一些内核数据，&lt;code&gt;syscall&lt;/code&gt;是执行一个系统调用，根据指定的参数&lt;code&gt;number&lt;/code&gt;和所有系统调用的接口来确定调用哪个系统调用，用于用户空间跟内核之间的数据交换，下面是&lt;code&gt;syscall&lt;/code&gt;函数原型及一些常用的&lt;code&gt;number&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//syscall - indirect system call
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define _GNU_SOURCE         &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/* See feature_test_macros(7) */&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/syscall.h&amp;gt;   /* For SYS_xxx definitions */&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 查看缓存内存页面的大小；打印用%ld 长整型。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_PAGESIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 查看内存的总页数；打印用%ld 长整型。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_PHYS_PAGES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 查看可以利用的总页数；打印用%ld 长整型。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_AVPHYS_PAGES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 查看 CPU 的个数；打印用%ld 长整。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_NPROCESSORS_CONF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 查看在使用的 CPU 个数；打印用%ld 长整。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_NPROCESSORS_ONLN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 计算内存大小。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_PAGESIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_PHYS_PAGES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 查看最大登录名长度；打印用%ld 长整。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_LOGIN_NAME_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 查看最大主机长度；打印用%ld 长整。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_HOST_NAME_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 每个进程运行时打开的文件数目；打印用%ld 长整。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_OPEN_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 查看每秒中跑过的运算速率；打印用%ld 长整。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_CLK_TCK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;使用-2-种方式-带和不带_s-后缀的宏-获取当前进程的-cpu-亲和性&#34;&gt;使用 2 种方式 (带和不带_S 后缀的宏) 获取当前进程的 CPU 亲和性&lt;/h3&gt;
&lt;p&gt;相关的宏通常都分为 2 种，一种是带&lt;code&gt;_S&lt;/code&gt;后缀的，一种不是不带&lt;code&gt;_S&lt;/code&gt;后缀的，从声明上看带&lt;code&gt;_S&lt;/code&gt;后缀的宏都多出一个参数 &lt;code&gt;setsize&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;从功能上看他们的区别是带&lt;code&gt;_S&lt;/code&gt;后缀的宏是用于操作动态申请的&lt;code&gt;CPU set(s)&lt;/code&gt;，所谓的动态申请其实就是使用宏 &lt;code&gt;CPU_ALLOC&lt;/code&gt; 申请，&lt;/p&gt;
&lt;p&gt;参数 &lt;code&gt;setsize&lt;/code&gt; 可以是通过宏 &lt;code&gt;CPU_ALLOC_SIZE&lt;/code&gt; 获得，两者的用法详见下面的例子。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define _GNU_SOURCE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sched.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#undef WITH_S
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef WITH_S
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* 获取逻辑 CPU 个数 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_NPROCESSORS_CONF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;pmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_ALLOC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;cpusize&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CPU_ALLOC_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_ZERO_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpusize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* 获取 CPU 亲和性 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sched_getaffinity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sched_getaffinity&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;CPU_FREE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CPU_ISSET_S&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpusize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x01&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;processor #%d is set&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;bitmask = %#lx&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_FREE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_ZERO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* 获取 CPU 亲和性 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sched_getaffinity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sched_getaffinity&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* 获取逻辑 CPU 个数 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_NPROCESSORS_CONF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CPU_ISSET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x01&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;processor #%d is set&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;bitmask = %#lx&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 直接运行，不设置亲和性，获取CPU亲和性为所有CPU都会被设置
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  Affinity git:(main)   ./bin/main 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #0 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #1 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #2 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #3 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #4 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #5 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #6 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #7 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #8 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #9 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #10 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #11 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #12 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #13 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #14 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #15 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #16 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #17 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #18 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #19 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #20 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #21 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #22 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #23 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #24 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #25 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #26 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #27 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #28 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #29 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #30 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #31 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bitmask = 0xffffffff
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 使用taskset设置亲和性，将main程序绑定到第1个CPU上，mask转化为16进制为0x1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  Affinity git:(main)  taskset 1 ./bin/main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #0 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bitmask = 0x1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 使用taskset设置亲和性，将main程序绑定到第1,3,5,7个CPU上，mask转化为16进制为0x55
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  Affinity git:(main)  taskset 55 ./bin/main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #0 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #2 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #4 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #6 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bitmask = 0x55
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 使用taskset设置亲和性，将main程序绑定到第1,2,3,4个CPU上，mask转化为16进制为0xf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  Affinity git:(main)  taskset F ./bin/main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #0 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #1 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #2 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #3 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bitmask = 0xf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;设置进程的-cpu-亲和性后再获取显示-cpu-亲和性&#34;&gt;设置进程的 CPU 亲和性后再获取显示 CPU 亲和性&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define _GNU_SOURCE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sched.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt; /* sysconf */&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt; /* exit */&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_ZERO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_SET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* add CPU0 to cpu set */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_SET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* add CPU2 to cpu set */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_SET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* add CPU3 to cpu set */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* 设置 CPU 亲和性 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sched_setaffinity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sched_setaffinity&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_ZERO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sched_getaffinity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sched_getaffinity&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;cm&#34;&gt;/* get logical cpu number */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_NPROCESSORS_CONF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CPU_ISSET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x01&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;processor #%d is set&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;bitmask = %#lx&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  Affinity git:(main) ✗ ./bin/main 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #0 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #2 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #3 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bitmask = 0xd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;设置线程的-cpu-属性后再获取显示-cpu-亲和性&#34;&gt;设置线程的 CPU 属性后再获取显示 CPU 亲和性&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define _GNU_SOURCE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;pthread.h&amp;gt; //不用再包含&amp;lt;sched.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;errno.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define handle_error_en(en, msg) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;pthread_t&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;thread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kr&#34;&gt;thread&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pthread_self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Set affinity mask to include CPUs 0 to 7 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_ZERO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;CPU_SET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pthread_setaffinity_np&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;thread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;handle_error_en&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;pthread_setaffinity_np&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Check the actual affinity mask assigned to the thread */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pthread_getaffinity_np&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;thread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;handle_error_en&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;pthread_getaffinity_np&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Set returned by pthread_getaffinity_np() contained:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_SETSIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//CPU_SETSIZE 是定义在&amp;lt;sched.h&amp;gt;中的宏，通常是 1024
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CPU_ISSET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cpuset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;    CPU %d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;j&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  Affinity git:(main) ./bin/main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Set returned by pthread_getaffinity_np() contained:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CPU 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CPU 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CPU 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CPU 3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CPU 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CPU 5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CPU 6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    CPU 7
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;使用-seched_setaffinity-设置线程的-cpu-亲和性&#34;&gt;使用 seched_setaffinity 设置线程的 CPU 亲和性&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define _GNU_SOURCE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sched.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/syscall.h&amp;gt; // syscall&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_ZERO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_SET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* add CPU0 to cpu set */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;CPU_SET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* add CPU2 to cpu set */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 获取线程 id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;tid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__NR_gettid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// or syscall(SYS_gettid);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 对指定线程 id 设置 CPU 亲和性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sched_setaffinity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;cpu_set_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;perror&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sched_setaffinity&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sysconf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_SC_NPROCESSORS_CONF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nrcpus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;CPU_ISSET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;bitmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0x01&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;processor #%d is set&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  Affinity git:(main) ./bin/main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #0 is set
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processor #2 is set
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;什么是中断亲和性&#34;&gt;什么是中断亲和性&lt;/h2&gt;
&lt;p&gt;计算机中，中断是一种电信号，由硬件产生并直接送到中断控制器上，再由中断控制器向 CPU 发送中断信号，CPU 检测到信号后，中断当前工作转而处理中断信号。CPU 会通知操作系统已经产生中断，操作系统就会对中断进行处理。
这里有篇推文：&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIyNjMxOTY0NA==&amp;amp;mid=2247484717&amp;amp;idx=1&amp;amp;sn=2c1dd6c389c8476eb4fd178c714eaafc&amp;amp;scene=21#wechat_redirect&#34;&gt;CPU 明明 8 个核，网卡为啥拼命折腾一号核？&lt;/a&gt;生动的解释了中断亲和性。&lt;/p&gt;
&lt;p&gt;默认情况下，Linux 中断响应会被平均分配到所有 CPU 核心上，势必会发生写新的数据和指令缓存，并与 CPU 核心上原有进程产生冲突，造成中断响应延迟，影响进程处理时间。为了解决这个问题，可以将中断（或进程）绑定到指定 CPU 核心上，中断（或进程）所需要指令代码和数据有更大概率位于指定 CPU 本地数据和指令缓存内，而不必进行新的写缓存，从而提高中断响应（或进程）的处理速度。&lt;/p&gt;
&lt;h2 id=&#34;中断亲和性的使用场景&#34;&gt;中断亲和性的使用场景&lt;/h2&gt;
&lt;p&gt;对于文件服务器、Web 服务器，把不同的网卡 IRQ 均衡绑定到不同的 CPU 上将会减轻某 CP 的负载，提高多个 CPU 整体处理中断的能力; 对于数据库服务器，把磁盘控制器绑到一个 CPU、把网卡绑定到另一个 CPU 将会提高数据库的响应时间、优化性能。&lt;br&gt;
合理的根据自己的生产环境和应用的特点来平衡 IRQ 中断有助于提高系统的整体吞吐能力和性能。&lt;/p&gt;
&lt;h2 id=&#34;中断绑定流程&#34;&gt;中断绑定流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;关闭中断平衡守护进程
中断平衡守护进程（irqbalance daemon）会周期性地将中断平均地公平地分配给各个 CPU 核心，默认开启。为了实现中断绑定，首先需要将中断平衡守护进程关闭。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;systemctl status irqbalance&lt;/code&gt;查看守护进程的运行状态&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ systemctl status irqbalance
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;● irqbalance.service - irqbalance daemon
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded: loaded &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;/lib/systemd/system/irqbalance.service&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; enabled&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; vendor preset: &lt;span class=&#34;nb&#34;&gt;enable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Active: active &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;running&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; since Thu 2022-05-19 14:46:20 CST&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; weeks &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; days ago
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Main PID: &lt;span class=&#34;m&#34;&gt;1062&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;irqbalance&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Tasks: &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;limit: 4915&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;CGroup: /system.slice/irqbalance.service
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        └─1062 /usr/sbin/irqbalance --foreground
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5月 &lt;span class=&#34;m&#34;&gt;19&lt;/span&gt; 14:46:20 zdd systemd&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;: Started irqbalance daemon.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;systemctl stop irqbalance&lt;/code&gt;关闭中断平衡守护进程，中断响应默认都会由 CPU0 核心处理。或者&lt;code&gt;systemctl disable irqbalance&lt;/code&gt;取消中断平衡守护进程开机重启。因为关闭中断平衡守护进程过于强硬，可以在不关闭中断平衡守护进程条件下，让某些 CPU 核心脱离中断平衡守护进程的管理。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;绑定中断
中断绑定时，需要关闭系统中断平衡守护进程&lt;code&gt;systemctl stop irqbalance&lt;/code&gt;计算机当前各种中断响应情况在 &lt;code&gt;/proc/interrupts&lt;/code&gt; 文件中。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202205281336182.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202205281336182.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
第一列是中断 ID 号，CPU N 列是中断在第 n 个 CPU 核心上的响应次数，倒数第二列是中断类型，最后一列是描述。&lt;/p&gt;
&lt;p&gt;利用 echo 命令将 CPU 掩码写入 &lt;code&gt;/proc/irq/中断 ID/smp_affinity&lt;/code&gt; 文件中，即可实现修改某一中断的 CPU 亲和性。例如&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; 0x0004 &amp;gt; /proc/irq /50/smp_affinity
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://www.cnblogs.com/lubinlew/p/cpu_affinity.html&#34;&gt;Linux 中 CPU 亲和性 (affinity) - LubinLew - 博客园&lt;/a&gt;
&lt;a href=&#34;https://blog.51cto.com/u_15302006/3075968&#34;&gt;操作系统底层技术——CPU 亲和性_mb60ed33cfc44fa 的技术博客_51CTO 博客&lt;/a&gt;
&lt;a href=&#34;https://blog.51cto.com/u_15484754/4907846&#34;&gt;linux 进程、线程与 CPU 的亲和性（affinity）_wx61d68abba262d 的技术博客_51CTO 博客&lt;/a&gt;
&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIyNjMxOTY0NA==&amp;amp;mid=2247484717&amp;amp;idx=1&amp;amp;sn=2c1dd6c389c8476eb4fd178c714eaafc&amp;amp;scene=21#wechat_redirect&#34;&gt;CPU 明明 8 个核，网卡为啥拼命折腾一号核？&lt;/a&gt;
&lt;a href=&#34;https://en.wikipedia.org/wiki/Processor_affinity&#34;&gt;Processor affinity - Wikipedia&lt;/a&gt;
&lt;a href=&#34;https://mp.weixin.qq.com/s/HwDqCk8vtMdSEVSCLHAsbg&#34;&gt;什么？一个核同时执行两个线程？&lt;/a&gt;
&lt;a href=&#34;https://www.cnblogs.com/wenqiang/p/6049978.html#!comments&#34;&gt;linux 进程、线程与 CPU 的亲和性（affinity） - zhangwju - 博客园&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="预备知识">预备知识</h2>
<p><a href="https://mp.weixin.qq.com/s/HwDqCk8vtMdSEVSCLHAsbg">超线程技术 (Hyper-Threading)</a>：就是利用特殊的硬件指令，把两个逻辑内核 (CPU core) 模拟成两个物理芯片，让单个处理器都能使用线程级并行计算，进而兼容多线程操作系统和软件，减少了 CPU 的闲置时间，提高的 CPU 的运行效率。</p>
<p>我们常听到的双核四线程/四核八线程指的就是支持超线程技术的CPU.</p>
<p><strong>物理 CPU</strong>：机器上安装的实际 CPU, 比如说你的主板上安装了一个 8 核 CPU，那么物理 CPU 个数就是 1 个，所以物理 CPU 个数就是主板上安装的 CPU 个数。</p>
<p><strong>逻辑 CPU</strong>：一般情况，我们认为一颗 CPU 可以有多核，加上 Intel 的超线程技术 (HT), 可以在逻辑上再分一倍数量的 CPU core 出来；</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">逻辑CPU数量 = 物理CPU数量 x CPU cores x 2(如果支持并开启HT) //前提是CPU的型号一致，如果不一致只能一个一个的加起来，不用直接乘以物理CPU数量
</span></span><span class="line"><span class="cl">//比如你的电脑安装了一块4核CPU，并且支持且开启了超线程（HT）技术，那么逻辑CPU数量 = 1 × 4 × 2 = 8
</span></span></code></pre></div><p><strong>Linux 下查看 CPU 相关信息</strong>, CPU 的信息主要都在<code>/proc/cupinfo</code>中。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 查看物理CPU个数
</span></span><span class="line"><span class="cl">➜  ~ cat /proc/cpuinfo|grep &#34;physical id&#34;|sort -u|wc -l
</span></span><span class="line"><span class="cl">32
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 查看每个物理CPU中core的个数(即核数)
</span></span><span class="line"><span class="cl">➜  ~ cat /proc/cpuinfo|grep &#34;cpu cores&#34;|uniq
</span></span><span class="line"><span class="cl">1
</span></span><span class="line"><span class="cl"># 或者
</span></span><span class="line"><span class="cl">➜    cat /proc/cpuinfo | grep &#39;process&#39; | sort | uniq | wc -l
</span></span><span class="line"><span class="cl">1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 查看逻辑CPU的个数
</span></span><span class="line"><span class="cl">➜  ~ cat /proc/cpuinfo|grep &#34;processor&#34;|wc -l
</span></span><span class="line"><span class="cl">32
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 查看CPU的名称型号
</span></span><span class="line"><span class="cl">➜  ~ cat /proc/cpuinfo|grep &#34;name&#34;|cut -f2 -d:|uniq
</span></span><span class="line"><span class="cl">Intel Xeon Processor (Skylake, IBRS)
</span></span></code></pre></div><p><strong>Linux 查看某个进程运行在哪个逻辑 CPU 上</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ps -eo pid,args,psr
</span></span></code></pre></div><ul>
<li><code>pid</code>：进程 ID</li>
<li><code>args</code>：该进程执行时传入的命令行参数</li>
<li><code>psr</code>：分配给进程的逻辑 CPU</li>
</ul>
<p>例子：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ps -eo pid,args,psr | grep firefox
</span></span><span class="line"><span class="cl">20118 /usr/lib/firefox/firefox -n  13
</span></span><span class="line"><span class="cl">20208 /usr/lib/firefox/firefox -c   9
</span></span><span class="line"><span class="cl">20266 /usr/lib/firefox/firefox -c  29
</span></span><span class="line"><span class="cl">20329 /usr/lib/firefox/firefox -c  24
</span></span><span class="line"><span class="cl">20499 /usr/lib/firefox/firefox -c   7
</span></span><span class="line"><span class="cl">20565 /usr/lib/firefox/firefox -c  15
</span></span><span class="line"><span class="cl">20596 /usr/lib/firefox/firefox -c  24
</span></span><span class="line"><span class="cl">20760 /usr/lib/firefox/firefox -c  18
</span></span><span class="line"><span class="cl">22110 /usr/lib/firefox/firefox -c  27
</span></span><span class="line"><span class="cl">25857 /usr/lib/firefox/firefox -c  28
</span></span><span class="line"><span class="cl">26347 /usr/lib/firefox/firefox -c  19
</span></span><span class="line"><span class="cl">26899 /usr/lib/firefox/firefox -c  29
</span></span></code></pre></div><p><strong>Linux 查看线程的 TID</strong></p>
<p>TID 就是 Thread ID，他和 POSIX 中<code>pthread_t</code>表示的线程 ID 完全不是同一个东西。</p>
<p>Linux 中的 POSIX 线程库实现的线程其实也是一个轻量级进程 (LWP),这个 TID 就是这个线程的真实 PID.</p>
<p>但是又不能通过<code>getpid()</code>函数获取，Linux 中定义了<code>gettid()</code>这个接口，但是通常都是未实现的，所以需要使用下面的方式获取 TID。</p>
<p>使用 API 获取：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/syscall.h&gt;  </span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="kt">pid_t</span> <span class="n">tid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">tid</span> <span class="o">=</span> <span class="nf">syscall</span><span class="p">(</span><span class="n">__NR_gettid</span><span class="p">);</span> <span class="c1">// or syscall(SYS_gettid)  
</span></span></span></code></pre></div><p>命令行方式获取：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 3种方法(推荐第三种方法)
</span></span><span class="line"><span class="cl">➜  ps -efL | grep prog_name
</span></span><span class="line"><span class="cl">➜  ls /proc/pid/task      //文件夹名即TID
</span></span><span class="line"><span class="cl">➜  ps -To &#39;pid,lwp,psr,cmd&#39; -p PID
</span></span></code></pre></div><h2 id="什么是-cpu-亲和性">什么是 CPU 亲和性</h2>
<p>CPU 的亲和性 (Affinity)，属于一种调度属性，可以绑定进程到指定 CPU 上。 换句话说，就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器。</p>
<p>为何会出现这种技术？在 SMP(Symmetric Multi-Processing 对称多处理) 架构下，调度器会试图保持进程在相同的 CPU 上运行，这意味着进程通常不会在处理器之间频繁迁移，进程迁移的频率小就意味着产生的负载小。</p>
<p>又如，每个 CPU 本身自己会有缓存，缓存着进程使用的信息，而进程可能会被操作系统调度到其他 CPU 上，如此，CPU 缓存命中率就低了，当绑定 CPU 后，程序就会一直在指定的 CPU 跑，不会由操作系统调度到其他 CPU 上，性能有一定的提高。</p>
<p><strong>软亲和性</strong>:  就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器，Linux 内核进程调度器天生就具有被称为 软 CPU 亲和性（affinity）的特性，这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的，因为进程迁移的频率小就意味着产生的负载小。</p>
<p><strong>硬亲和性</strong>：简单来说就是利用 Linux 内核提供给用户的 API，强行将进程或者线程绑定到某一个指定的 CPU 核运行。</p>
<p>CPU affinity 使用位掩码 (bitmask) 表示，每一位都表示一个 CPU, 置 1 表示&quot;绑定&quot;。最低位表示第一个逻辑 CPU, 最高位表示最后一个逻辑 CPU。</p>
<p>CPU affinity 典型的表示方法是使用 16 进制，具体如下。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">0b00000000000000000000000000000001
</span></span><span class="line"><span class="cl">= 0x00000001
</span></span><span class="line"><span class="cl">表示 processor #0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0b00000000000000000000000001010101
</span></span><span class="line"><span class="cl">= 0x00000055
</span></span><span class="line"><span class="cl">表示 processors #0, #2, #4, #6
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0b11111111111111111111111111111111
</span></span><span class="line"><span class="cl">= 0xFFFFFFFF
</span></span><span class="line"><span class="cl">表示所有 processors (#0 through #31)
</span></span></code></pre></div><h2 id="使用taskset命令设置-cpu-亲和性">使用<code>taskset</code>命令设置 CPU 亲和性</h2>
<p><strong>命令行形式</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">taskset [options] mask command [arg]...
</span></span><span class="line"><span class="cl">taskset [options] -p [mask] pid
</span></span></code></pre></div><p><strong>参数解析</strong>
[OPTIONS]taskset 的可选参数</p>
<ul>
<li>
<p><code>-a, --all-tasks</code> (旧版本中没有这个选项)
这个选项涉及到了linux中TID的概念,他会将一个进程中所有的TID都执行一次CPU亲和性设置.
TID 就是 Thread ID，他和 POSIX 中 pthread_t 表示的线程 ID 完全不是同一个东西。
Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),这个TID就是这个线程的真实PID.</p>
</li>
<li>
<p><code>-p, --pid</code>
操作已存在的PID,而不是加载一个新的程序</p>
</li>
<li>
<p><code>-c, --cpu-list</code>
声明CPU的亲和力使用数字表示而不是用位掩码表示. 例如 0,5,7,9-11.</p>
</li>
<li>
<p><code>-h, --help</code>
显示帮助信息</p>
</li>
<li>
<p><code>-V, --version</code>
显示版本信息</p>
</li>
<li>
<p><code>mask</code> : cpu 亲和性，当没有<code>-c</code>选项时，其值前无论有没有<code>0x</code>标记都是 16 进制的，当有<code>-c</code>选项时，其值是十进制的。</p>
</li>
<li>
<p><code>command</code> : 命令或者可执行程序</p>
</li>
<li>
<p><code>pid</code> : 进程 ID，可以通过<code>ps/top/pidof</code>等命令获取</p>
</li>
</ul>
<p><code>[arg]</code> command 的参数</p>
<h3 id="实例">实例</h3>
<h4 id="使用指定的-cpu-亲和性运行一个新程序">使用指定的 CPU 亲和性运行一个新程序</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">taskset <span class="o">[</span>-c<span class="o">]</span> mask <span class="nb">command</span> <span class="o">[</span>arg<span class="o">]</span>...
</span></span><span class="line"><span class="cl"><span class="c1"># 举例: 使用CPU0运行ls命令显示/etc/init.d下的所有内容</span>
</span></span><span class="line"><span class="cl">taskset -c <span class="m">0</span> ls -al /etc/init.d/
</span></span></code></pre></div><h4 id="显示已经运行的进程的-cpu-亲和性">显示已经运行的进程的 CPU 亲和性</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">taskset -p pid
</span></span><span class="line"><span class="cl"><span class="c1"># 举例:查看init进程(PID=1)的CPU亲和性</span>
</span></span><span class="line"><span class="cl">taskset -p <span class="m">1</span>
</span></span></code></pre></div><h4 id="改变已经运行进程的-cpu-亲和性">改变已经运行进程的 CPU 亲和性</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">taskset -p[c] mask pid
</span></span><span class="line"><span class="cl">举例:打开2个终端,在第一个终端运行top命令,第二个终端中
</span></span><span class="line"><span class="cl"> 　　首先运行:[~]# ps -eo pid,args,psr | grep top #获取top命令的pid和其所运行的CPU号
</span></span><span class="line"><span class="cl"> 　　其次运行:[~]# taskset -cp 新的CPU号 pid       #更改top命令运行的CPU号
</span></span><span class="line"><span class="cl"> 　　最后运行:[~]# ps -eo pid,args,psr | grep top #查看是否更改成功
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ~ ps -eo pid,args,psr | grep top
</span></span><span class="line"><span class="cl">2501 nautilus-desktop             24
</span></span><span class="line"><span class="cl">2634 /usr/libexec/xdg-desktop-po  18
</span></span><span class="line"><span class="cl">2658 /usr/libexec/xdg-desktop-po  11
</span></span><span class="line"><span class="cl">23848 top                           6
</span></span><span class="line"><span class="cl">➜  ~ taskset -cp 10 23848
</span></span><span class="line"><span class="cl">pid 23848&#39;s current affinity list: 0-31
</span></span><span class="line"><span class="cl">pid 23848&#39;s new affinity list: 10
</span></span><span class="line"><span class="cl">➜  ~ ps -eo pid,args,psr | grep top
</span></span><span class="line"><span class="cl"> 2501 nautilus-desktop             24
</span></span><span class="line"><span class="cl"> 2634 /usr/libexec/xdg-desktop-po  18
</span></span><span class="line"><span class="cl"> 2658 /usr/libexec/xdg-desktop-po  11
</span></span><span class="line"><span class="cl">23848 top                          10
</span></span></code></pre></div><blockquote>
<p>一个用户要设定一个进程的 CPU 亲和性，如果目标进程是该用户的，则可以设置，如果是其他用户的，则会设置失败，提示 Operation not permitted.当然 root 用户没有任何限制。
任何用户都可以获取任意一个进程的 CPU 亲和性。</p>
</blockquote>
<h2 id="程序-api-实现硬亲和性">程序 API 实现硬亲和性</h2>
<p>以下实验使用的源码可以从<a href="https://github.com/Dunky-Z/learning-linux/tree/main/Affinity">这个仓库</a>获取。</p>
<p>以下是一些设置亲和性时会用到的宏定义及函数：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define _GNU_SOURCE
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sched.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;pthread.h&gt; //注意&lt;pthread.h&gt;包含&lt;sched.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* MACRO */</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 对 CPU 集初始化，将其设置为空集
</span></span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_ZERO</span><span class="p">(</span><span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_ZERO_S</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 将 CPU 加入到 CPU 集中
</span></span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_SET</span><span class="p">(</span><span class="kt">int</span> <span class="n">cpu</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_SET_S</span><span class="p">(</span><span class="kt">int</span> <span class="n">cpu</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 将 CPU 从 CPU 集中移除
</span></span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_CLR</span><span class="p">(</span><span class="kt">int</span> <span class="n">cpu</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_CLR_S</span><span class="p">(</span><span class="kt">int</span> <span class="n">cpu</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 判断 CPU 是否在 CPU 集中
</span></span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="nf">CPU_ISSET</span><span class="p">(</span><span class="kt">int</span> <span class="n">cpu</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="nf">CPU_ISSET_S</span><span class="p">(</span><span class="kt">int</span> <span class="n">cpu</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// 计算 CPU 集的大小
</span></span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_COUNT</span><span class="p">(</span><span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_COUNT_S</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1">// The following macros perform logical operations on CPU sets 
</span></span></span><span class="line"><span class="cl">        <span class="cm">/* Store the logical AND of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_AND</span><span class="p">(</span><span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">destset</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset1</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_AND_S</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">destset</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset1</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="cm">/* Store the logical OR of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_OR</span><span class="p">(</span><span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">destset</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset1</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_OR_S</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">destset</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset1</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="cm">/* Store  the logical XOR of the sets srcset1 and srcset2 in destset (which may be one of the source sets). */</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_XOR</span><span class="p">(</span><span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">destset</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset1</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_XOR_S</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">destset</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset1</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">srcset2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="cm">/* Test whether two CPU set contain exactly the same CPUs. */</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="nf">CPU_EQUAL</span><span class="p">(</span><span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set1</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="nf">CPU_EQUAL_S</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">setsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set1</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set2</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="cm">/* The following macros are used to allocate and deallocate CPU sets: */</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/* Allocate a CPU set large enough to hold CPUs in the range 0 to num_cpus-1 */</span>
</span></span><span class="line"><span class="cl">        <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="nf">CPU_ALLOC</span><span class="p">(</span><span class="kt">int</span> <span class="n">num_cpus</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">        <span class="cm">/* Return the size in bytes of the CPU set that would be needed to  hold  CPUs  in the  range 0 to num_cpus-1. 
</span></span></span><span class="line"><span class="cl"><span class="cm">           This macro provides the value that can be used for the setsize argument in the CPU_*_S() macros */</span>
</span></span><span class="line"><span class="cl">        <span class="kt">size_t</span> <span class="nf">CPU_ALLOC_SIZE</span><span class="p">(</span><span class="kt">int</span> <span class="n">num_cpus</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="cm">/* Free a CPU set previously allocated by CPU_ALLOC(). */</span>
</span></span><span class="line"><span class="cl">        <span class="kt">void</span> <span class="nf">CPU_FREE</span><span class="p">(</span><span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">set</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* API */</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/*该函数设置进程为 pid 的这个进程，让它运行在 mask 所设定的 CPU 上。如果 pid 的值为 0,
</span></span></span><span class="line"><span class="cl"><span class="cm">    *则表示指定的是当前进程，使当前进程运行在 mask 所设定的那些 CPU 上.
</span></span></span><span class="line"><span class="cl"><span class="cm">    *第二个参数 cpusetsize 是 mask 所指定的数的长度。通常设定为 sizeof(cpu_set_t).
</span></span></span><span class="line"><span class="cl"><span class="cm">    *如果当前 pid 所指定的进程此时没有运行在 mask 所指定的任意一个 CPU 上，
</span></span></span><span class="line"><span class="cl"><span class="cm">    *则该指定的进程会从其它 CPU 上迁移到 mask 的指定的一个 CPU 上运行.
</span></span></span><span class="line"><span class="cl"><span class="cm">    */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="nf">sched_setaffinity</span><span class="p">(</span><span class="kt">pid_t</span> <span class="n">pid</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">cpusetsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">mask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/*该函数获得 pid 所指示的进程的 CPU 位掩码，并将该掩码返回到 mask 所指向的结构中.
</span></span></span><span class="line"><span class="cl"><span class="cm">    *即获得指定 pid 当前可以运行在哪些 CPU 上.
</span></span></span><span class="line"><span class="cl"><span class="cm">    *同样，如果 pid 的值为 0.也表示的是当前进程
</span></span></span><span class="line"><span class="cl"><span class="cm">    */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="nf">sched_getaffinity</span><span class="p">(</span><span class="kt">pid_t</span> <span class="n">pid</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">cpusetsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">mask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="cm">/* set CPU affinity attribute in thread attributes object */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="nf">pthread_attr_setaffinity_np</span><span class="p">(</span><span class="kt">pthread_attr_t</span> <span class="o">*</span><span class="n">attr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">cpusetsize</span><span class="p">,</span> <span class="k">const</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* get CPU affinity attribute in thread attributes object */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="nf">pthread_attr_getaffinity_np</span><span class="p">(</span><span class="k">const</span> <span class="kt">pthread_attr_t</span> <span class="o">*</span><span class="n">attr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">cpusetsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="cm">/* set CPU affinity of a thread */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="nf">pthread_setaffinity_np</span><span class="p">(</span><span class="kt">pthread_t</span> <span class="kr">thread</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">cpusetsize</span><span class="p">,</span> <span class="k">const</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* get CPU affinity of a thread */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="nf">pthread_getaffinity_np</span><span class="p">(</span><span class="kt">pthread_t</span> <span class="kr">thread</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">cpusetsize</span><span class="p">,</span> <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">cpuset</span><span class="p">);</span>
</span></span></code></pre></div><p>程序中会使用<code>syscall</code>来获取一些内核数据，<code>syscall</code>是执行一个系统调用，根据指定的参数<code>number</code>和所有系统调用的接口来确定调用哪个系统调用，用于用户空间跟内核之间的数据交换，下面是<code>syscall</code>函数原型及一些常用的<code>number</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//syscall - indirect system call
</span></span></span><span class="line"><span class="cl"><span class="cp">#define _GNU_SOURCE         </span><span class="cm">/* See feature_test_macros(7) */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/syscall.h&gt;   /* For SYS_xxx definitions */</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">syscall</span><span class="p">(</span><span class="kt">int</span> <span class="n">number</span><span class="p">,</span> <span class="p">...);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 查看缓存内存页面的大小；打印用%ld 长整型。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_PAGESIZE</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl"><span class="c1">// 查看内存的总页数；打印用%ld 长整型。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_PHYS_PAGES</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 查看可以利用的总页数；打印用%ld 长整型。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_AVPHYS_PAGES</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 查看 CPU 的个数；打印用%ld 长整。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_NPROCESSORS_CONF</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 查看在使用的 CPU 个数；打印用%ld 长整。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_NPROCESSORS_ONLN</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 计算内存大小。
</span></span></span><span class="line"><span class="cl"><span class="p">(</span><span class="kt">long</span> <span class="kt">long</span><span class="p">)</span><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_PAGESIZE</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="kt">long</span> <span class="kt">long</span><span class="p">)</span><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_PHYS_PAGES</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 查看最大登录名长度；打印用%ld 长整。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_LOGIN_NAME_MAX</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 查看最大主机长度；打印用%ld 长整。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_HOST_NAME_MAX</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl"><span class="c1">// 每个进程运行时打开的文件数目；打印用%ld 长整。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_OPEN_MAX</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl"><span class="c1">// 查看每秒中跑过的运算速率；打印用%ld 长整。
</span></span></span><span class="line"><span class="cl"><span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_CLK_TCK</span><span class="p">)</span> 
</span></span></code></pre></div><h3 id="使用-2-种方式-带和不带_s-后缀的宏-获取当前进程的-cpu-亲和性">使用 2 种方式 (带和不带_S 后缀的宏) 获取当前进程的 CPU 亲和性</h3>
<p>相关的宏通常都分为 2 种，一种是带<code>_S</code>后缀的，一种不是不带<code>_S</code>后缀的，从声明上看带<code>_S</code>后缀的宏都多出一个参数 <code>setsize</code>。</p>
<p>从功能上看他们的区别是带<code>_S</code>后缀的宏是用于操作动态申请的<code>CPU set(s)</code>，所谓的动态申请其实就是使用宏 <code>CPU_ALLOC</code> 申请，</p>
<p>参数 <code>setsize</code> 可以是通过宏 <code>CPU_ALLOC_SIZE</code> 获得，两者的用法详见下面的例子。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define _GNU_SOURCE
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sched.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#undef WITH_S
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef WITH_S
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">nrcpus</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">cpu_set_t</span> <span class="o">*</span><span class="n">pmask</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">size_t</span> <span class="n">cpusize</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">bitmask</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* 获取逻辑 CPU 个数 */</span>
</span></span><span class="line"><span class="cl">    <span class="n">nrcpus</span> <span class="o">=</span> <span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_NPROCESSORS_CONF</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">pmask</span> <span class="o">=</span> <span class="nf">CPU_ALLOC</span><span class="p">(</span><span class="n">nrcpus</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">cpusize</span> <span class="o">=</span> <span class="nf">CPU_ALLOC_SIZE</span><span class="p">(</span><span class="n">nrcpus</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_ZERO_S</span><span class="p">(</span><span class="n">cpusize</span><span class="p">,</span> <span class="n">pmask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* 获取 CPU 亲和性 */</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">sched_getaffinity</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">cpusize</span><span class="p">,</span> <span class="n">pmask</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">perror</span><span class="p">(</span><span class="s">&#34;sched_getaffinity&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">CPU_FREE</span><span class="p">(</span><span class="n">pmask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">nrcpus</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">CPU_ISSET_S</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">cpusize</span><span class="p">,</span> <span class="n">pmask</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">bitmask</span> <span class="o">|=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="mh">0x01</span> <span class="o">&lt;&lt;</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;processor #%d is set</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;bitmask = %#lx</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">bitmask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_FREE</span><span class="p">(</span><span class="n">pmask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">nrcpus</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">cpu_set_t</span> <span class="n">mask</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">bitmask</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_ZERO</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* 获取 CPU 亲和性 */</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">sched_getaffinity</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">cpu_set_t</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">perror</span><span class="p">(</span><span class="s">&#34;sched_getaffinity&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* 获取逻辑 CPU 个数 */</span>
</span></span><span class="line"><span class="cl">    <span class="n">nrcpus</span> <span class="o">=</span> <span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_NPROCESSORS_CONF</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">nrcpus</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">CPU_ISSET</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">bitmask</span> <span class="o">|=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="mh">0x01</span> <span class="o">&lt;&lt;</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;processor #%d is set</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;bitmask = %#lx</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">bitmask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 直接运行，不设置亲和性，获取CPU亲和性为所有CPU都会被设置
</span></span><span class="line"><span class="cl">➜  Affinity git:(main)   ./bin/main 
</span></span><span class="line"><span class="cl">processor #0 is set
</span></span><span class="line"><span class="cl">processor #1 is set
</span></span><span class="line"><span class="cl">processor #2 is set
</span></span><span class="line"><span class="cl">processor #3 is set
</span></span><span class="line"><span class="cl">processor #4 is set
</span></span><span class="line"><span class="cl">processor #5 is set
</span></span><span class="line"><span class="cl">processor #6 is set
</span></span><span class="line"><span class="cl">processor #7 is set
</span></span><span class="line"><span class="cl">processor #8 is set
</span></span><span class="line"><span class="cl">processor #9 is set
</span></span><span class="line"><span class="cl">processor #10 is set
</span></span><span class="line"><span class="cl">processor #11 is set
</span></span><span class="line"><span class="cl">processor #12 is set
</span></span><span class="line"><span class="cl">processor #13 is set
</span></span><span class="line"><span class="cl">processor #14 is set
</span></span><span class="line"><span class="cl">processor #15 is set
</span></span><span class="line"><span class="cl">processor #16 is set
</span></span><span class="line"><span class="cl">processor #17 is set
</span></span><span class="line"><span class="cl">processor #18 is set
</span></span><span class="line"><span class="cl">processor #19 is set
</span></span><span class="line"><span class="cl">processor #20 is set
</span></span><span class="line"><span class="cl">processor #21 is set
</span></span><span class="line"><span class="cl">processor #22 is set
</span></span><span class="line"><span class="cl">processor #23 is set
</span></span><span class="line"><span class="cl">processor #24 is set
</span></span><span class="line"><span class="cl">processor #25 is set
</span></span><span class="line"><span class="cl">processor #26 is set
</span></span><span class="line"><span class="cl">processor #27 is set
</span></span><span class="line"><span class="cl">processor #28 is set
</span></span><span class="line"><span class="cl">processor #29 is set
</span></span><span class="line"><span class="cl">processor #30 is set
</span></span><span class="line"><span class="cl">processor #31 is set
</span></span><span class="line"><span class="cl">bitmask = 0xffffffff
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 使用taskset设置亲和性，将main程序绑定到第1个CPU上，mask转化为16进制为0x1
</span></span><span class="line"><span class="cl">➜  Affinity git:(main)  taskset 1 ./bin/main
</span></span><span class="line"><span class="cl">processor #0 is set
</span></span><span class="line"><span class="cl">bitmask = 0x1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 使用taskset设置亲和性，将main程序绑定到第1,3,5,7个CPU上，mask转化为16进制为0x55
</span></span><span class="line"><span class="cl">➜  Affinity git:(main)  taskset 55 ./bin/main
</span></span><span class="line"><span class="cl">processor #0 is set
</span></span><span class="line"><span class="cl">processor #2 is set
</span></span><span class="line"><span class="cl">processor #4 is set
</span></span><span class="line"><span class="cl">processor #6 is set
</span></span><span class="line"><span class="cl">bitmask = 0x55
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 使用taskset设置亲和性，将main程序绑定到第1,2,3,4个CPU上，mask转化为16进制为0xf
</span></span><span class="line"><span class="cl">➜  Affinity git:(main)  taskset F ./bin/main
</span></span><span class="line"><span class="cl">processor #0 is set
</span></span><span class="line"><span class="cl">processor #1 is set
</span></span><span class="line"><span class="cl">processor #2 is set
</span></span><span class="line"><span class="cl">processor #3 is set
</span></span><span class="line"><span class="cl">bitmask = 0xf
</span></span></code></pre></div><h3 id="设置进程的-cpu-亲和性后再获取显示-cpu-亲和性">设置进程的 CPU 亲和性后再获取显示 CPU 亲和性</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define _GNU_SOURCE
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sched.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt; /* sysconf */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt; /* exit */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">nrcpus</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">cpu_set_t</span> <span class="n">mask</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">bitmask</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_ZERO</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_SET</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span> <span class="cm">/* add CPU0 to cpu set */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_SET</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span> <span class="cm">/* add CPU2 to cpu set */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_SET</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span> <span class="cm">/* add CPU3 to cpu set */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* 设置 CPU 亲和性 */</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">sched_setaffinity</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">cpu_set_t</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">    <span class="p">{</span>   
</span></span><span class="line"><span class="cl">        <span class="nf">perror</span><span class="p">(</span><span class="s">&#34;sched_setaffinity&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_ZERO</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">sched_getaffinity</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">cpu_set_t</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">    <span class="p">{</span>   
</span></span><span class="line"><span class="cl">        <span class="nf">perror</span><span class="p">(</span><span class="s">&#34;sched_getaffinity&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">       <span class="cm">/* get logical cpu number */</span>
</span></span><span class="line"><span class="cl">    <span class="n">nrcpus</span> <span class="o">=</span> <span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_NPROCESSORS_CONF</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">nrcpus</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">CPU_ISSET</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">bitmask</span> <span class="o">|=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="mh">0x01</span> <span class="o">&lt;&lt;</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;processor #%d is set</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;bitmask = %#lx</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">bitmask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  Affinity git:(main) ✗ ./bin/main 
</span></span><span class="line"><span class="cl">processor #0 is set
</span></span><span class="line"><span class="cl">processor #2 is set
</span></span><span class="line"><span class="cl">processor #3 is set
</span></span><span class="line"><span class="cl">bitmask = 0xd
</span></span></code></pre></div><h3 id="设置线程的-cpu-属性后再获取显示-cpu-亲和性">设置线程的 CPU 属性后再获取显示 CPU 亲和性</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define _GNU_SOURCE
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;pthread.h&gt; //不用再包含&lt;sched.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;errno.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#define handle_error_en(en, msg) \
</span></span></span><span class="line"><span class="cl"><span class="cp">        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span>
</span></span><span class="line"><span class="cl"><span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">s</span><span class="p">,</span> <span class="n">j</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">cpu_set_t</span> <span class="n">cpuset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">pthread_t</span> <span class="kr">thread</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kr">thread</span> <span class="o">=</span> <span class="nf">pthread_self</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="cm">/* Set affinity mask to include CPUs 0 to 7 */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_ZERO</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="mi">8</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nf">CPU_SET</span><span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="n">s</span> <span class="o">=</span> <span class="nf">pthread_setaffinity_np</span><span class="p">(</span><span class="kr">thread</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">cpu_set_t</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">s</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">handle_error_en</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="s">&#34;pthread_setaffinity_np&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="cm">/* Check the actual affinity mask assigned to the thread */</span>
</span></span><span class="line"><span class="cl">    <span class="n">s</span> <span class="o">=</span> <span class="nf">pthread_getaffinity_np</span><span class="p">(</span><span class="kr">thread</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">cpu_set_t</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">cpuset</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">s</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">handle_error_en</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="s">&#34;pthread_getaffinity_np&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;Set returned by pthread_getaffinity_np() contained:</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">CPU_SETSIZE</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="c1">//CPU_SETSIZE 是定义在&lt;sched.h&gt;中的宏，通常是 1024
</span></span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">CPU_ISSET</span><span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cpuset</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;    CPU %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">j</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  Affinity git:(main) ./bin/main
</span></span><span class="line"><span class="cl">Set returned by pthread_getaffinity_np() contained:
</span></span><span class="line"><span class="cl">    CPU 0
</span></span><span class="line"><span class="cl">    CPU 1
</span></span><span class="line"><span class="cl">    CPU 2
</span></span><span class="line"><span class="cl">    CPU 3
</span></span><span class="line"><span class="cl">    CPU 4
</span></span><span class="line"><span class="cl">    CPU 5
</span></span><span class="line"><span class="cl">    CPU 6
</span></span><span class="line"><span class="cl">    CPU 7
</span></span></code></pre></div><h3 id="使用-seched_setaffinity-设置线程的-cpu-亲和性">使用 seched_setaffinity 设置线程的 CPU 亲和性</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define _GNU_SOURCE
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sched.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/syscall.h&gt; // syscall</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">pid_t</span> <span class="n">tid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">nrcpus</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">cpu_set_t</span> <span class="n">mask</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">bitmask</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_ZERO</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_SET</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span> <span class="cm">/* add CPU0 to cpu set */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">CPU_SET</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">);</span> <span class="cm">/* add CPU2 to cpu set */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 获取线程 id
</span></span></span><span class="line"><span class="cl">    <span class="n">tid</span> <span class="o">=</span> <span class="nf">syscall</span><span class="p">(</span><span class="n">__NR_gettid</span><span class="p">);</span> <span class="c1">// or syscall(SYS_gettid);
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 对指定线程 id 设置 CPU 亲和性
</span></span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">sched_setaffinity</span><span class="p">(</span><span class="n">tid</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">cpu_set_t</span><span class="p">),</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> 
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">perror</span><span class="p">(</span><span class="s">&#34;sched_setaffinity&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">nrcpus</span> <span class="o">=</span> <span class="nf">sysconf</span><span class="p">(</span><span class="n">_SC_NPROCESSORS_CONF</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">nrcpus</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">CPU_ISSET</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mask</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">bitmask</span> <span class="o">|=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="mh">0x01</span> <span class="o">&lt;&lt;</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;processor #%d is set</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  Affinity git:(main) ./bin/main
</span></span><span class="line"><span class="cl">processor #0 is set
</span></span><span class="line"><span class="cl">processor #2 is set
</span></span></code></pre></div><h2 id="什么是中断亲和性">什么是中断亲和性</h2>
<p>计算机中，中断是一种电信号，由硬件产生并直接送到中断控制器上，再由中断控制器向 CPU 发送中断信号，CPU 检测到信号后，中断当前工作转而处理中断信号。CPU 会通知操作系统已经产生中断，操作系统就会对中断进行处理。
这里有篇推文：<a href="https://mp.weixin.qq.com/s?__biz=MzIyNjMxOTY0NA==&amp;mid=2247484717&amp;idx=1&amp;sn=2c1dd6c389c8476eb4fd178c714eaafc&amp;scene=21#wechat_redirect">CPU 明明 8 个核，网卡为啥拼命折腾一号核？</a>生动的解释了中断亲和性。</p>
<p>默认情况下，Linux 中断响应会被平均分配到所有 CPU 核心上，势必会发生写新的数据和指令缓存，并与 CPU 核心上原有进程产生冲突，造成中断响应延迟，影响进程处理时间。为了解决这个问题，可以将中断（或进程）绑定到指定 CPU 核心上，中断（或进程）所需要指令代码和数据有更大概率位于指定 CPU 本地数据和指令缓存内，而不必进行新的写缓存，从而提高中断响应（或进程）的处理速度。</p>
<h2 id="中断亲和性的使用场景">中断亲和性的使用场景</h2>
<p>对于文件服务器、Web 服务器，把不同的网卡 IRQ 均衡绑定到不同的 CPU 上将会减轻某 CP 的负载，提高多个 CPU 整体处理中断的能力; 对于数据库服务器，把磁盘控制器绑到一个 CPU、把网卡绑定到另一个 CPU 将会提高数据库的响应时间、优化性能。<br>
合理的根据自己的生产环境和应用的特点来平衡 IRQ 中断有助于提高系统的整体吞吐能力和性能。</p>
<h2 id="中断绑定流程">中断绑定流程</h2>
<ol>
<li>
<p>关闭中断平衡守护进程
中断平衡守护进程（irqbalance daemon）会周期性地将中断平均地公平地分配给各个 CPU 核心，默认开启。为了实现中断绑定，首先需要将中断平衡守护进程关闭。</p>
<ul>
<li><code>systemctl status irqbalance</code>查看守护进程的运行状态</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">➜  ~ systemctl status irqbalance
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">● irqbalance.service - irqbalance daemon
</span></span><span class="line"><span class="cl">Loaded: loaded <span class="o">(</span>/lib/systemd/system/irqbalance.service<span class="p">;</span> enabled<span class="p">;</span> vendor preset: <span class="nb">enable</span>
</span></span><span class="line"><span class="cl">Active: active <span class="o">(</span>running<span class="o">)</span> since Thu 2022-05-19 14:46:20 CST<span class="p">;</span> <span class="m">1</span> weeks <span class="m">1</span> days ago
</span></span><span class="line"><span class="cl">Main PID: <span class="m">1062</span> <span class="o">(</span>irqbalance<span class="o">)</span>
</span></span><span class="line"><span class="cl">    Tasks: <span class="m">2</span> <span class="o">(</span>limit: 4915<span class="o">)</span>
</span></span><span class="line"><span class="cl">CGroup: /system.slice/irqbalance.service
</span></span><span class="line"><span class="cl">        └─1062 /usr/sbin/irqbalance --foreground
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">5月 <span class="m">19</span> 14:46:20 zdd systemd<span class="o">[</span>1<span class="o">]</span>: Started irqbalance daemon.
</span></span></code></pre></div><ul>
<li><code>systemctl stop irqbalance</code>关闭中断平衡守护进程，中断响应默认都会由 CPU0 核心处理。或者<code>systemctl disable irqbalance</code>取消中断平衡守护进程开机重启。因为关闭中断平衡守护进程过于强硬，可以在不关闭中断平衡守护进程条件下，让某些 CPU 核心脱离中断平衡守护进程的管理。</li>
</ul>
</li>
<li>
<p>绑定中断
中断绑定时，需要关闭系统中断平衡守护进程<code>systemctl stop irqbalance</code>计算机当前各种中断响应情况在 <code>/proc/interrupts</code> 文件中。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202205281336182.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202205281336182.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>
第一列是中断 ID 号，CPU N 列是中断在第 n 个 CPU 核心上的响应次数，倒数第二列是中断类型，最后一列是描述。</p>
<p>利用 echo 命令将 CPU 掩码写入 <code>/proc/irq/中断 ID/smp_affinity</code> 文件中，即可实现修改某一中断的 CPU 亲和性。例如</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> 0x0004 &gt; /proc/irq /50/smp_affinity
</span></span></code></pre></div></li>
</ol>
<h2 id="参考资料">参考资料</h2>
<p><a href="https://www.cnblogs.com/lubinlew/p/cpu_affinity.html">Linux 中 CPU 亲和性 (affinity) - LubinLew - 博客园</a>
<a href="https://blog.51cto.com/u_15302006/3075968">操作系统底层技术——CPU 亲和性_mb60ed33cfc44fa 的技术博客_51CTO 博客</a>
<a href="https://blog.51cto.com/u_15484754/4907846">linux 进程、线程与 CPU 的亲和性（affinity）_wx61d68abba262d 的技术博客_51CTO 博客</a>
<a href="https://mp.weixin.qq.com/s?__biz=MzIyNjMxOTY0NA==&amp;mid=2247484717&amp;idx=1&amp;sn=2c1dd6c389c8476eb4fd178c714eaafc&amp;scene=21#wechat_redirect">CPU 明明 8 个核，网卡为啥拼命折腾一号核？</a>
<a href="https://en.wikipedia.org/wiki/Processor_affinity">Processor affinity - Wikipedia</a>
<a href="https://mp.weixin.qq.com/s/HwDqCk8vtMdSEVSCLHAsbg">什么？一个核同时执行两个线程？</a>
<a href="https://www.cnblogs.com/wenqiang/p/6049978.html#!comments">linux 进程、线程与 CPU 的亲和性（affinity） - zhangwju - 博客园</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>QEMU 源码分析-QOM</title>
      <link>https://lifeislife.cn/posts/qemu%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-qom/</link>
      <pubDate>Wed, 09 Mar 2022 16:02:19 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-qom/</guid>
      <description>&lt;h2 id=&#34;qom-简介&#34;&gt;QOM 简介&lt;/h2&gt;
&lt;p&gt;QOM(QEMU Object Model) 是 QEMU 的一个模块，用于描述虚拟机的结构，包括虚拟机的 CPU、内存、硬盘、网络、输入输出设备等。QEMU 为了方便整个系统的构建，实现了自己的一套的面向对象机制，也就是 QOM(QEMU Object Model)。它能够方便的表示各个设备（Device）与总线（Bus）之间的关系。&lt;/p&gt;
&lt;p&gt;这个模型主要包含四个结构体：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Object: 是所有对象的 基类 Base Object&lt;/li&gt;
&lt;li&gt;ObjectClass: 是所有类对象的基类&lt;/li&gt;
&lt;li&gt;TypeInfo：是用户用来定义一个 Type 的工具型的数据结构&lt;/li&gt;
&lt;li&gt;TypeImpl：TypeInfo 抽象数据结构，TypeInfo 的属性与 TypeImpl 的属性对应&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 QEMU 里要初始化一个对象需要完成四步：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将 TypeInfo 注册 TypeImpl&lt;/li&gt;
&lt;li&gt;实例化 Class（ObjectClass）&lt;/li&gt;
&lt;li&gt;实例化 Object&lt;/li&gt;
&lt;li&gt;添加 Property&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/15-09-19-4995177f1aeb782fadaf586f8f5c8b32-qemu-QOM%E5%88%86%E6%9E%90.drawio%20-2--1a4eac.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/15-09-19-4995177f1aeb782fadaf586f8f5c8b32-qemu-QOM%E5%88%86%E6%9E%90.drawio%20-2--1a4eac.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;qom-中的面向对象&#34;&gt;QOM 中的面向对象&lt;/h2&gt;
&lt;h3 id=&#34;继承&#34;&gt;继承&lt;/h3&gt;
&lt;p&gt;在 QEMU 中通过 &lt;strong&gt;TypeInfo&lt;/strong&gt; 来定义一个类。&lt;/p&gt;
&lt;p&gt;例如 &lt;code&gt;x86_base_cpu_type_info&lt;/code&gt; 就是一个 &lt;code&gt;class&lt;/code&gt;，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x86_base_cpu_type_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;X86_CPU_TYPE_NAME&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;base&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_X86_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x86_cpu_base_class_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;利用结构体包含来实现继承&lt;/strong&gt;。这应该是所有的语言实现继承的方法，在 C++ 中，结构体包含的操作被语言内部实现了，而 C 语言需要自己实现。&lt;/p&gt;
&lt;p&gt;例如 &lt;code&gt;x86_cpu_type_info&lt;/code&gt; 的 &lt;code&gt;parent&lt;/code&gt; 是 &lt;code&gt;cpu_type_info&lt;/code&gt;, 他们的结构体分别是 &lt;code&gt;X86CPU&lt;/code&gt; 和 &lt;code&gt;CPUState&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x86_cpu_type_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_X86_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;X86CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpu_type_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_DEVICE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CPUState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;X86CPU&lt;/code&gt; 中包含一个 &lt;code&gt;CPUState&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86CPU&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/*&amp;lt; private &amp;gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;CPUState&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;parent_obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/*&amp;lt; public &amp;gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;CPUNegativeOffsetState&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;neg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;静态成员&#34;&gt;静态成员&lt;/h3&gt;
&lt;p&gt;静态成员变量可以在类的多个对象中访问，但是要在类外声明。&lt;strong&gt;不同对象访问的其实是同一个实体，静态成员变量被多个对象共享&lt;/strong&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x86_cpu_type_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_X86_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;X86CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x86_cpu_initfn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_post_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x86_cpu_post_initfn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;abstract&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;X86CPUClass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x86_cpu_common_class_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &lt;code&gt;X86CPU&lt;/code&gt; 描述的是非静态成员，而 &lt;code&gt;X86CPUClass&lt;/code&gt; 描述的是静态的成员。也就是说&lt;code&gt;class_init&lt;/code&gt;初始化静态成员，&lt;code&gt;instance_init&lt;/code&gt;初始化非静态成员。&lt;/p&gt;
&lt;p&gt;那么何时初始化静态成员呢？首先得告诉系统，咱有&lt;code&gt;class_init&lt;/code&gt;这个初始化函数，等需要的时候随时可以调用它初始化，所有先解决如何将这个初始化函数注册到系统中？&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;target/i386/cpu.c&lt;/code&gt;最后使用了&lt;code&gt;type_init&lt;/code&gt;。在&lt;code&gt;qemu/include/qemu/module.h&lt;/code&gt;中有一个&lt;code&gt;type_init&lt;/code&gt;宏定义，除了&lt;code&gt;type_init&lt;/code&gt;还有其他宏，比如&lt;code&gt;block_init&lt;/code&gt;，&lt;code&gt;opts_init&lt;/code&gt;等。每个宏都表示一类&lt;code&gt;module&lt;/code&gt;，通过&lt;code&gt;module_init&lt;/code&gt;构造出来。我们展开这个宏，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__attribute__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;constructor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;do_qemu_init_x86_cpu_register_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;register_module_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x86_cpu_register_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MODULE_INIT_QOM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过 &lt;code&gt;gcc&lt;/code&gt; 扩展属性&lt;code&gt;__attribute__((constructor))&lt;/code&gt;可以让 &lt;code&gt;do_qemu_init_x86_cpu_register_types&lt;/code&gt; 在运行 &lt;code&gt;main&lt;/code&gt; 函数之前运行。 &lt;code&gt;register_module_init&lt;/code&gt; 会让 &lt;code&gt;x86_cpu_register_types&lt;/code&gt; 这个函数挂载到 &lt;code&gt;init_type_list[MODULE_INIT_QOM]&lt;/code&gt; 这个链表上。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210907133931.svg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210907133931.svg&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;到底，所有的 &lt;code&gt;TypeInfo&lt;/code&gt; 通过 &lt;code&gt;type_init&lt;/code&gt; 都被放到 &lt;code&gt;type_table&lt;/code&gt; 上了，之后通过 &lt;code&gt;Typeinfo&lt;/code&gt; 的名称调用 &lt;code&gt;type_table_lookup&lt;/code&gt; 获取到 &lt;code&gt;TypeImpl&lt;/code&gt; 了。&lt;/p&gt;
&lt;p&gt;到这里，将&lt;code&gt;TYPE_X86_CPU&lt;/code&gt;注册进类系统，包括其初始化函数，这部分也就是 QEMU 中类型的构造。那么何时调用静态成员初始化函数呢？也就是类型的初始化。&lt;/p&gt;
&lt;p&gt;静态成员是所有的对象公用的，其初始化显然要发生在所有的对象初始化之前。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;qemu_init&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;select_machine&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;object_class_get_list&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;object_class_foreach&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;g_hash_table_foreach&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &lt;span class=&#34;n&#34;&gt;object_class_foreach_tramp&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                            &lt;span class=&#34;n&#34;&gt;type_initialize&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                &lt;span class=&#34;n&#34;&gt;type_initialize&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                    &lt;span class=&#34;n&#34;&gt;x86_cpu_common_class_init&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;select_machine&lt;/code&gt; 需要获取所有的 &lt;code&gt;TYPE_MACHINE&lt;/code&gt; 的 &lt;code&gt;class&lt;/code&gt;, 其首先会调用所有的&lt;code&gt;class_list&lt;/code&gt;，其会遍历 &lt;code&gt;type_table&lt;/code&gt;，遍历的过程中会顺带 &lt;code&gt;type_initialize&lt;/code&gt; 所有的 &lt;code&gt;TypeImpl&lt;/code&gt; 进而调用的 &lt;code&gt;class_init&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;说完类型的初始化，再讲一下对象的初始化，也就是初始化非静态成员，也就是&lt;code&gt;instance_init&lt;/code&gt;在何时被调用？&lt;/p&gt;
&lt;p&gt;对象初始化，通过调用 &lt;code&gt;object_new&lt;/code&gt; 来实现初始化。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;object_initialize_with_type&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;初始化一个空的 :&lt;code&gt;Object::properties&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;object_init_with_type&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;如果 &lt;code&gt;object&lt;/code&gt; 有 &lt;code&gt;parent&lt;/code&gt;，那么调用 &lt;code&gt;object_init_with_type&lt;/code&gt; 首先初始化 &lt;code&gt;parent&lt;/code&gt; 的&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;TypeImpl::instance_init&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;qemu_init&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;qmp_x_exit_preconfig&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;qemu_init_board&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;machine_run_board_init&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;pc_init_v6_1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &lt;span class=&#34;n&#34;&gt;pc_init1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                            &lt;span class=&#34;n&#34;&gt;x86_cpus_init&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                &lt;span class=&#34;n&#34;&gt;x86_cpu_new&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                    &lt;span class=&#34;n&#34;&gt;object_new&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                        &lt;span class=&#34;n&#34;&gt;object_new_with_type&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                            &lt;span class=&#34;n&#34;&gt;object_initialize_with_type&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                &lt;span class=&#34;n&#34;&gt;object_init_with_type&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                    &lt;span class=&#34;n&#34;&gt;x86_cpu_initfn&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;多态&#34;&gt;多态&lt;/h3&gt;
&lt;p&gt;多态是指同一操作作用于不同的对象，可以有不同的解释，产生不同的执行结果。为了实现多态，QOM 实现了一个非常重要的功能，就是动态类型转换。我们可以使用相关的函数，将一个&lt;code&gt;Object&lt;/code&gt;的指针在运行时转换为子类对象的指针，可以将一个&lt;code&gt;ObjectClass&lt;/code&gt;的指针在运行时转换为子类的指针。这样就可以调用子类中定义的函数指针来完成相应的功能。&lt;/p&gt;
&lt;p&gt;QEMU 定义了一些列的宏封来进行动态类型转换：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//include/qom/object.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * DECLARE_INSTANCE_CHECKER:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @InstanceType: instance struct name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @OBJ_NAME: the object name in uppercase with underscore separators
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @TYPENAME: type name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Direct usage of this macro should be avoided, and the complete
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT_DECLARE_TYPE macro is recommended instead.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * This macro will provide the instance type cast functions for a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * QOM type.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    static inline G_GNUC_UNUSED InstanceType * \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    OBJ_NAME(const void *obj) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    { return OBJECT_CHECK(InstanceType, obj, TYPENAME); }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * DECLARE_CLASS_CHECKERS:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @ClassType: class struct name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @OBJ_NAME: the object name in uppercase with underscore separators
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @TYPENAME: type name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Direct usage of this macro should be avoided, and the complete
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT_DECLARE_TYPE macro is recommended instead.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * This macro will provide the class type cast functions for a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * QOM type.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    static inline G_GNUC_UNUSED ClassType * \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    OBJ_NAME##_GET_CLASS(const void *obj) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    { return OBJECT_GET_CLASS(ClassType, obj, TYPENAME); } \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    static inline G_GNUC_UNUSED ClassType * \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    OBJ_NAME##_CLASS(const void *klass) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    { return OBJECT_CLASS_CHECK(ClassType, klass, TYPENAME); }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * DECLARE_OBJ_CHECKERS:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @InstanceType: instance struct name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @ClassType: class struct name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @OBJ_NAME: the object name in uppercase with underscore separators
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @TYPENAME: type name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Direct usage of this macro should be avoided, and the complete
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT_DECLARE_TYPE macro is recommended instead.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * This macro will provide the three standard type cast functions for a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * QOM type.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define DECLARE_OBJ_CHECKERS(InstanceType, ClassType, OBJ_NAME, TYPENAME) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT_DECLARE_TYPE:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @InstanceType: instance struct name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @ClassType: class struct name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * This macro is typically used in a header file, and will:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *   - create the typedefs for the object and class structs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *   - register the type for use with g_autoptr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *   - provide three standard type cast functions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * The object struct and class struct need to be declared manually.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define OBJECT_DECLARE_TYPE(InstanceType, ClassType, MODULE_OBJ_NAME) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    typedef struct InstanceType InstanceType; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    typedef struct ClassType ClassType; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    G_DEFINE_AUTOPTR_CLEANUP_FUNC(InstanceType, object_unref) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    DECLARE_OBJ_CHECKERS(InstanceType, ClassType, \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;                         MODULE_OBJ_NAME, TYPE_##MODULE_OBJ_NAME)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @obj: A derivative of #Object
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Converts an object to a #Object.  Since all objects are #Objects,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * this function will always succeed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define OBJECT(obj) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    ((Object *)(obj))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT_CLASS:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @class: A derivative of #ObjectClass.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Converts a class to an #ObjectClass.  Since all objects are #Objects,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * this function will always succeed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define OBJECT_CLASS(class) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    ((ObjectClass *)(class))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT_CHECK:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @type: The C type to use for the return value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @obj: A derivative of @type to cast.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @name: The QOM typename of @type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * A type safe version of @object_dynamic_cast_assert.  Typically each class
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * will define a macro based on this type to perform type safe dynamic_casts to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * this object type.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * If an invalid object is passed to this function, a run time assert will be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * generated.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define OBJECT_CHECK(type, obj, name) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    ((type *)object_dynamic_cast_assert(OBJECT(obj), (name), \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;                                        __FILE__, __LINE__, __func__))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT_CLASS_CHECK:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @class_type: The C type to use for the return value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @class: A derivative class of @class_type to cast.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @name: the QOM typename of @class_type.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * A type safe version of @object_class_dynamic_cast_assert.  This macro is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * typically wrapped by each type to perform type safe casts of a class to a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * specific class type.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define OBJECT_CLASS_CHECK(class_type, class, name) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    ((class_type *)object_class_dynamic_cast_assert(OBJECT_CLASS(class), (name), \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;                                               __FILE__, __LINE__, __func__))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * OBJECT_GET_CLASS:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @class: The C type to use for the return value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @obj: The object to obtain the class for.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @name: The QOM typename of @obj.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * This function will return a specific class for a given object.  Its generally
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * used by each type to provide a type safe macro to get a specific class type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * from an object.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define OBJECT_GET_CLASS(class, obj, name) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以&lt;code&gt;OBJECT_DECLARE_TYPE(X86CPU, X86CPUClass, X86_CPU)&lt;/code&gt;为例，宏展开如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86CPU&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86CPUClass&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86CPUClass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;G_DEFINE_AUTOPTR_CLEANUP_FUNC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;X86CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;object_unref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;inline&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;G_GNUC_UNUSED&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86CPU&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;X86_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;X86CPU&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;object_dynamic_cast_assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TYPE_X86_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s&#34;&gt;&amp;#34;~/core/vn/docs/qemu/res/qom-macros.c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__func__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;inline&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;G_GNUC_UNUSED&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86CPUClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;X86_CPU_GET_CLASS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;X86CPUClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;object_class_dynamic_cast_assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ObjectClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;object_get_class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))),&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TYPE_X86_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s&#34;&gt;&amp;#34;~/core/vn/docs/qemu/res/qom-macros.c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__func__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;inline&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;G_GNUC_UNUSED&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86CPUClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;X86_CPU_CLASS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;klass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;X86CPUClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;object_class_dynamic_cast_assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ObjectClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;klass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TYPE_X86_CPU&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s&#34;&gt;&amp;#34;~/core/vn/docs/qemu/res/qom-macros.c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__func__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;OBJECT_DECLARE_TYPE&lt;/code&gt;通常在头文件中使用，效果是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建了&lt;code&gt;X86CPU&lt;/code&gt;和&lt;code&gt;X86CPUClass&lt;/code&gt;的&lt;code&gt;typedef&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;用&lt;code&gt;G_DEFINE_AUTOPTR_CLEANUP_FUNC&lt;/code&gt;注册类型&lt;/li&gt;
&lt;li&gt;创建了三个类型转换函数
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;X86_CPU&lt;/code&gt; : 将任何一个 &lt;code&gt;object&lt;/code&gt; 指针 转换为 &lt;code&gt;X86CPU&lt;/code&gt;（Object 转子对象）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;X86_CPU_GET_CLASS&lt;/code&gt; : 根据 &lt;code&gt;object&lt;/code&gt; 指针获取到 &lt;code&gt;X86CPUClass&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;X86_CPU_CLASS&lt;/code&gt; : 根据 &lt;code&gt;ObjectClass&lt;/code&gt; 指针转换到 &lt;code&gt;X86CPUClass&lt;/code&gt;（基类转子类）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里的转换依赖内存布局，子类型的第一个成员总是基类型。子类转基类就很容易，只需要强制类型转换就可以实现。&lt;/p&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://martins3.github.io/qemu/qom.html#init&#34;&gt;QEMU 中的面向对象 : QOM | Deep Dark Fantasy&lt;/a&gt;
&lt;a href=&#34;https://www.jianshu.com/p/4a9d26abb44d&#34;&gt;浅谈 QEMU 的对象系统 - 简书&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="qom-简介">QOM 简介</h2>
<p>QOM(QEMU Object Model) 是 QEMU 的一个模块，用于描述虚拟机的结构，包括虚拟机的 CPU、内存、硬盘、网络、输入输出设备等。QEMU 为了方便整个系统的构建，实现了自己的一套的面向对象机制，也就是 QOM(QEMU Object Model)。它能够方便的表示各个设备（Device）与总线（Bus）之间的关系。</p>
<p>这个模型主要包含四个结构体：</p>
<ul>
<li>Object: 是所有对象的 基类 Base Object</li>
<li>ObjectClass: 是所有类对象的基类</li>
<li>TypeInfo：是用户用来定义一个 Type 的工具型的数据结构</li>
<li>TypeImpl：TypeInfo 抽象数据结构，TypeInfo 的属性与 TypeImpl 的属性对应</li>
</ul>
<p>在 QEMU 里要初始化一个对象需要完成四步：</p>
<ul>
<li>将 TypeInfo 注册 TypeImpl</li>
<li>实例化 Class（ObjectClass）</li>
<li>实例化 Object</li>
<li>添加 Property</li>
</ul>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/15-09-19-4995177f1aeb782fadaf586f8f5c8b32-qemu-QOM%E5%88%86%E6%9E%90.drawio%20-2--1a4eac.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/15-09-19-4995177f1aeb782fadaf586f8f5c8b32-qemu-QOM%E5%88%86%E6%9E%90.drawio%20-2--1a4eac.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="qom-中的面向对象">QOM 中的面向对象</h2>
<h3 id="继承">继承</h3>
<p>在 QEMU 中通过 <strong>TypeInfo</strong> 来定义一个类。</p>
<p>例如 <code>x86_base_cpu_type_info</code> 就是一个 <code>class</code>，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">TypeInfo</span> <span class="n">x86_base_cpu_type_info</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="nf">X86_CPU_TYPE_NAME</span><span class="p">(</span><span class="s">&#34;base&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">TYPE_X86_CPU</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">.</span><span class="n">class_init</span> <span class="o">=</span> <span class="n">x86_cpu_base_class_init</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p><strong>利用结构体包含来实现继承</strong>。这应该是所有的语言实现继承的方法，在 C++ 中，结构体包含的操作被语言内部实现了，而 C 语言需要自己实现。</p>
<p>例如 <code>x86_cpu_type_info</code> 的 <code>parent</code> 是 <code>cpu_type_info</code>, 他们的结构体分别是 <code>X86CPU</code> 和 <code>CPUState</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">TypeInfo</span> <span class="n">x86_cpu_type_info</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">TYPE_X86_CPU</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">TYPE_CPU</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">instance_size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">X86CPU</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">TypeInfo</span> <span class="n">cpu_type_info</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">TYPE_CPU</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">TYPE_DEVICE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">instance_size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CPUState</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>在 <code>X86CPU</code> 中包含一个 <code>CPUState</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">X86CPU</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/*&lt; private &gt;*/</span>
</span></span><span class="line"><span class="cl">    <span class="n">CPUState</span> <span class="n">parent_obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/*&lt; public &gt;*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">CPUNegativeOffsetState</span> <span class="n">neg</span><span class="p">;</span>
</span></span></code></pre></div><h3 id="静态成员">静态成员</h3>
<p>静态成员变量可以在类的多个对象中访问，但是要在类外声明。<strong>不同对象访问的其实是同一个实体，静态成员变量被多个对象共享</strong>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">TypeInfo</span> <span class="n">x86_cpu_type_info</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">TYPE_X86_CPU</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">TYPE_CPU</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">instance_size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">X86CPU</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">instance_init</span> <span class="o">=</span> <span class="n">x86_cpu_initfn</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">instance_post_init</span> <span class="o">=</span> <span class="n">x86_cpu_post_initfn</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">abstract</span> <span class="o">=</span> <span class="nb">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">class_size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">X86CPUClass</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">class_init</span> <span class="o">=</span> <span class="n">x86_cpu_common_class_init</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>其中 <code>X86CPU</code> 描述的是非静态成员，而 <code>X86CPUClass</code> 描述的是静态的成员。也就是说<code>class_init</code>初始化静态成员，<code>instance_init</code>初始化非静态成员。</p>
<p>那么何时初始化静态成员呢？首先得告诉系统，咱有<code>class_init</code>这个初始化函数，等需要的时候随时可以调用它初始化，所有先解决如何将这个初始化函数注册到系统中？</p>
<p>在<code>target/i386/cpu.c</code>最后使用了<code>type_init</code>。在<code>qemu/include/qemu/module.h</code>中有一个<code>type_init</code>宏定义，除了<code>type_init</code>还有其他宏，比如<code>block_init</code>，<code>opts_init</code>等。每个宏都表示一类<code>module</code>，通过<code>module_init</code>构造出来。我们展开这个宏，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">__attribute__</span><span class="p">((</span><span class="n">constructor</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="nf">do_qemu_init_x86_cpu_register_types</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">register_module_init</span><span class="p">(</span><span class="n">x86_cpu_register_types</span><span class="p">,</span> <span class="n">MODULE_INIT_QOM</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>通过 <code>gcc</code> 扩展属性<code>__attribute__((constructor))</code>可以让 <code>do_qemu_init_x86_cpu_register_types</code> 在运行 <code>main</code> 函数之前运行。 <code>register_module_init</code> 会让 <code>x86_cpu_register_types</code> 这个函数挂载到 <code>init_type_list[MODULE_INIT_QOM]</code> 这个链表上。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210907133931.svg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210907133931.svg" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>到底，所有的 <code>TypeInfo</code> 通过 <code>type_init</code> 都被放到 <code>type_table</code> 上了，之后通过 <code>Typeinfo</code> 的名称调用 <code>type_table_lookup</code> 获取到 <code>TypeImpl</code> 了。</p>
<p>到这里，将<code>TYPE_X86_CPU</code>注册进类系统，包括其初始化函数，这部分也就是 QEMU 中类型的构造。那么何时调用静态成员初始化函数呢？也就是类型的初始化。</p>
<p>静态成员是所有的对象公用的，其初始化显然要发生在所有的对象初始化之前。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">main</span>
</span></span><span class="line"><span class="cl">    <span class="n">qemu_init</span> 
</span></span><span class="line"><span class="cl">        <span class="n">select_machine</span> 
</span></span><span class="line"><span class="cl">            <span class="n">object_class_get_list</span> 
</span></span><span class="line"><span class="cl">                <span class="n">object_class_foreach</span> 
</span></span><span class="line"><span class="cl">                    <span class="n">g_hash_table_foreach</span> 
</span></span><span class="line"><span class="cl">                        <span class="n">object_class_foreach_tramp</span> 
</span></span><span class="line"><span class="cl">                            <span class="n">type_initialize</span> 
</span></span><span class="line"><span class="cl">                                <span class="n">type_initialize</span> 
</span></span><span class="line"><span class="cl">                                    <span class="n">x86_cpu_common_class_init</span> 
</span></span></code></pre></div><p><code>select_machine</code> 需要获取所有的 <code>TYPE_MACHINE</code> 的 <code>class</code>, 其首先会调用所有的<code>class_list</code>，其会遍历 <code>type_table</code>，遍历的过程中会顺带 <code>type_initialize</code> 所有的 <code>TypeImpl</code> 进而调用的 <code>class_init</code>。</p>
<p>说完类型的初始化，再讲一下对象的初始化，也就是初始化非静态成员，也就是<code>instance_init</code>在何时被调用？</p>
<p>对象初始化，通过调用 <code>object_new</code> 来实现初始化。</p>
<ul>
<li><code>object_initialize_with_type</code>
<ul>
<li>初始化一个空的 :<code>Object::properties</code></li>
<li><code>object_init_with_type</code>
<ul>
<li>如果 <code>object</code> 有 <code>parent</code>，那么调用 <code>object_init_with_type</code> 首先初始化 <code>parent</code> 的</li>
<li>调用<code>TypeImpl::instance_init</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">main</span> 
</span></span><span class="line"><span class="cl">    <span class="n">qemu_init</span> 
</span></span><span class="line"><span class="cl">        <span class="n">qmp_x_exit_preconfig</span> 
</span></span><span class="line"><span class="cl">            <span class="n">qemu_init_board</span> 
</span></span><span class="line"><span class="cl">                <span class="n">machine_run_board_init</span> 
</span></span><span class="line"><span class="cl">                    <span class="n">pc_init_v6_1</span> 
</span></span><span class="line"><span class="cl">                        <span class="n">pc_init1</span> 
</span></span><span class="line"><span class="cl">                            <span class="n">x86_cpus_init</span> 
</span></span><span class="line"><span class="cl">                                <span class="n">x86_cpu_new</span> 
</span></span><span class="line"><span class="cl">                                    <span class="n">object_new</span> 
</span></span><span class="line"><span class="cl">                                        <span class="n">object_new_with_type</span> 
</span></span><span class="line"><span class="cl">                                            <span class="n">object_initialize_with_type</span> 
</span></span><span class="line"><span class="cl">                                                <span class="n">object_init_with_type</span> 
</span></span><span class="line"><span class="cl">                                                    <span class="n">x86_cpu_initfn</span> 
</span></span></code></pre></div><h3 id="多态">多态</h3>
<p>多态是指同一操作作用于不同的对象，可以有不同的解释，产生不同的执行结果。为了实现多态，QOM 实现了一个非常重要的功能，就是动态类型转换。我们可以使用相关的函数，将一个<code>Object</code>的指针在运行时转换为子类对象的指针，可以将一个<code>ObjectClass</code>的指针在运行时转换为子类的指针。这样就可以调用子类中定义的函数指针来完成相应的功能。</p>
<p>QEMU 定义了一些列的宏封来进行动态类型转换：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">//include/qom/object.h
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * DECLARE_INSTANCE_CHECKER:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @InstanceType: instance struct name
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @OBJ_NAME: the object name in uppercase with underscore separators
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @TYPENAME: type name
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Direct usage of this macro should be avoided, and the complete
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT_DECLARE_TYPE macro is recommended instead.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * This macro will provide the instance type cast functions for a
</span></span></span><span class="line"><span class="cl"><span class="cm"> * QOM type.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    static inline G_GNUC_UNUSED InstanceType * \
</span></span></span><span class="line"><span class="cl"><span class="cp">    OBJ_NAME(const void *obj) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    { return OBJECT_CHECK(InstanceType, obj, TYPENAME); }
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * DECLARE_CLASS_CHECKERS:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @ClassType: class struct name
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @OBJ_NAME: the object name in uppercase with underscore separators
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @TYPENAME: type name
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Direct usage of this macro should be avoided, and the complete
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT_DECLARE_TYPE macro is recommended instead.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * This macro will provide the class type cast functions for a
</span></span></span><span class="line"><span class="cl"><span class="cm"> * QOM type.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    static inline G_GNUC_UNUSED ClassType * \
</span></span></span><span class="line"><span class="cl"><span class="cp">    OBJ_NAME##_GET_CLASS(const void *obj) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    { return OBJECT_GET_CLASS(ClassType, obj, TYPENAME); } \
</span></span></span><span class="line"><span class="cl"><span class="cp">    \
</span></span></span><span class="line"><span class="cl"><span class="cp">    static inline G_GNUC_UNUSED ClassType * \
</span></span></span><span class="line"><span class="cl"><span class="cp">    OBJ_NAME##_CLASS(const void *klass) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    { return OBJECT_CLASS_CHECK(ClassType, klass, TYPENAME); }
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * DECLARE_OBJ_CHECKERS:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @InstanceType: instance struct name
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @ClassType: class struct name
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @OBJ_NAME: the object name in uppercase with underscore separators
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @TYPENAME: type name
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Direct usage of this macro should be avoided, and the complete
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT_DECLARE_TYPE macro is recommended instead.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * This macro will provide the three standard type cast functions for a
</span></span></span><span class="line"><span class="cl"><span class="cm"> * QOM type.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define DECLARE_OBJ_CHECKERS(InstanceType, ClassType, OBJ_NAME, TYPENAME) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    \
</span></span></span><span class="line"><span class="cl"><span class="cp">    DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT_DECLARE_TYPE:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @InstanceType: instance struct name
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @ClassType: class struct name
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @MODULE_OBJ_NAME: the object name in uppercase with underscore separators
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * This macro is typically used in a header file, and will:
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> *   - create the typedefs for the object and class structs
</span></span></span><span class="line"><span class="cl"><span class="cm"> *   - register the type for use with g_autoptr
</span></span></span><span class="line"><span class="cl"><span class="cm"> *   - provide three standard type cast functions
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * The object struct and class struct need to be declared manually.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define OBJECT_DECLARE_TYPE(InstanceType, ClassType, MODULE_OBJ_NAME) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    typedef struct InstanceType InstanceType; \
</span></span></span><span class="line"><span class="cl"><span class="cp">    typedef struct ClassType ClassType; \
</span></span></span><span class="line"><span class="cl"><span class="cp">    \
</span></span></span><span class="line"><span class="cl"><span class="cp">    G_DEFINE_AUTOPTR_CLEANUP_FUNC(InstanceType, object_unref) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    \
</span></span></span><span class="line"><span class="cl"><span class="cp">    DECLARE_OBJ_CHECKERS(InstanceType, ClassType, \
</span></span></span><span class="line"><span class="cl"><span class="cp">                         MODULE_OBJ_NAME, TYPE_##MODULE_OBJ_NAME)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @obj: A derivative of #Object
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Converts an object to a #Object.  Since all objects are #Objects,
</span></span></span><span class="line"><span class="cl"><span class="cm"> * this function will always succeed.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define OBJECT(obj) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    ((Object *)(obj))
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT_CLASS:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @class: A derivative of #ObjectClass.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Converts a class to an #ObjectClass.  Since all objects are #Objects,
</span></span></span><span class="line"><span class="cl"><span class="cm"> * this function will always succeed.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define OBJECT_CLASS(class) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    ((ObjectClass *)(class))
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT_CHECK:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @type: The C type to use for the return value.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @obj: A derivative of @type to cast.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @name: The QOM typename of @type
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * A type safe version of @object_dynamic_cast_assert.  Typically each class
</span></span></span><span class="line"><span class="cl"><span class="cm"> * will define a macro based on this type to perform type safe dynamic_casts to
</span></span></span><span class="line"><span class="cl"><span class="cm"> * this object type.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * If an invalid object is passed to this function, a run time assert will be
</span></span></span><span class="line"><span class="cl"><span class="cm"> * generated.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define OBJECT_CHECK(type, obj, name) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    ((type *)object_dynamic_cast_assert(OBJECT(obj), (name), \
</span></span></span><span class="line"><span class="cl"><span class="cp">                                        __FILE__, __LINE__, __func__))
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT_CLASS_CHECK:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @class_type: The C type to use for the return value.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @class: A derivative class of @class_type to cast.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @name: the QOM typename of @class_type.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * A type safe version of @object_class_dynamic_cast_assert.  This macro is
</span></span></span><span class="line"><span class="cl"><span class="cm"> * typically wrapped by each type to perform type safe casts of a class to a
</span></span></span><span class="line"><span class="cl"><span class="cm"> * specific class type.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define OBJECT_CLASS_CHECK(class_type, class, name) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    ((class_type *)object_class_dynamic_cast_assert(OBJECT_CLASS(class), (name), \
</span></span></span><span class="line"><span class="cl"><span class="cp">                                               __FILE__, __LINE__, __func__))
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * OBJECT_GET_CLASS:
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @class: The C type to use for the return value.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @obj: The object to obtain the class for.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @name: The QOM typename of @obj.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * This function will return a specific class for a given object.  Its generally
</span></span></span><span class="line"><span class="cl"><span class="cm"> * used by each type to provide a type safe macro to get a specific class type
</span></span></span><span class="line"><span class="cl"><span class="cm"> * from an object.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define OBJECT_GET_CLASS(class, obj, name) \
</span></span></span><span class="line"><span class="cl"><span class="cp">    OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
</span></span></span></code></pre></div><p>以<code>OBJECT_DECLARE_TYPE(X86CPU, X86CPUClass, X86_CPU)</code>为例，宏展开如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="n">X86CPU</span> <span class="n">X86CPU</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="n">X86CPUClass</span> <span class="n">X86CPUClass</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nf">G_DEFINE_AUTOPTR_CLEANUP_FUNC</span><span class="p">(</span><span class="n">X86CPU</span><span class="p">,</span> <span class="n">object_unref</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kr">inline</span> <span class="n">G_GNUC_UNUSED</span> <span class="n">X86CPU</span> <span class="o">*</span><span class="nf">X86_CPU</span><span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">((</span><span class="n">X86CPU</span> <span class="o">*</span><span class="p">)</span><span class="nf">object_dynamic_cast_assert</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="p">((</span><span class="n">Object</span> <span class="o">*</span><span class="p">)(</span><span class="n">obj</span><span class="p">)),</span> <span class="p">(</span><span class="n">TYPE_X86_CPU</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="s">&#34;~/core/vn/docs/qemu/res/qom-macros.c&#34;</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="n">__func__</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kr">inline</span> <span class="n">G_GNUC_UNUSED</span> <span class="n">X86CPUClass</span> <span class="o">*</span><span class="nf">X86_CPU_GET_CLASS</span><span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">((</span><span class="n">X86CPUClass</span> <span class="o">*</span><span class="p">)</span><span class="nf">object_class_dynamic_cast_assert</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="p">((</span><span class="n">ObjectClass</span> <span class="o">*</span><span class="p">)(</span><span class="nf">object_get_class</span><span class="p">(((</span><span class="n">Object</span> <span class="o">*</span><span class="p">)(</span><span class="n">obj</span><span class="p">))))),</span> <span class="p">(</span><span class="n">TYPE_X86_CPU</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="s">&#34;~/core/vn/docs/qemu/res/qom-macros.c&#34;</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="n">__func__</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kr">inline</span> <span class="n">G_GNUC_UNUSED</span> <span class="n">X86CPUClass</span> <span class="o">*</span><span class="nf">X86_CPU_CLASS</span><span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">klass</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="p">((</span><span class="n">X86CPUClass</span> <span class="o">*</span><span class="p">)</span><span class="nf">object_class_dynamic_cast_assert</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="p">((</span><span class="n">ObjectClass</span> <span class="o">*</span><span class="p">)(</span><span class="n">klass</span><span class="p">)),</span> <span class="p">(</span><span class="n">TYPE_X86_CPU</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">      <span class="s">&#34;~/core/vn/docs/qemu/res/qom-macros.c&#34;</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="n">__func__</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>OBJECT_DECLARE_TYPE</code>通常在头文件中使用，效果是：</p>
<ul>
<li>创建了<code>X86CPU</code>和<code>X86CPUClass</code>的<code>typedef</code></li>
<li>用<code>G_DEFINE_AUTOPTR_CLEANUP_FUNC</code>注册类型</li>
<li>创建了三个类型转换函数
<ul>
<li><code>X86_CPU</code> : 将任何一个 <code>object</code> 指针 转换为 <code>X86CPU</code>（Object 转子对象）</li>
<li><code>X86_CPU_GET_CLASS</code> : 根据 <code>object</code> 指针获取到 <code>X86CPUClass</code></li>
<li><code>X86_CPU_CLASS</code> : 根据 <code>ObjectClass</code> 指针转换到 <code>X86CPUClass</code>（基类转子类）</li>
</ul>
</li>
</ul>
<p>这里的转换依赖内存布局，子类型的第一个成员总是基类型。子类转基类就很容易，只需要强制类型转换就可以实现。</p>
<h2 id="参考">参考</h2>
<p><a href="https://martins3.github.io/qemu/qom.html#init">QEMU 中的面向对象 : QOM | Deep Dark Fantasy</a>
<a href="https://www.jianshu.com/p/4a9d26abb44d">浅谈 QEMU 的对象系统 - 简书</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>QEMU 源码分析-内存虚拟化</title>
      <link>https://lifeislife.cn/posts/qemu%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E5%86%85%E5%AD%98%E8%99%9A%E6%8B%9F%E5%8C%96/</link>
      <pubDate>Tue, 25 Jan 2022 13:42:11 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E5%86%85%E5%AD%98%E8%99%9A%E6%8B%9F%E5%8C%96/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;1.大部分转载自&lt;a href=&#34;https://abelsu7.top/2019/07/07/kvm-memory-virtualization/&#34;&gt;QEMU 内存虚拟化源码分析 | Keep Coding | 苏易北&lt;/a&gt;
2.原文源码为 QEMU1.2.0，版本较旧，部分源码内容根据 QEMU6.2 版本修改
3.部分内容根据自己理解补充添加&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;概述&#34;&gt;概述&lt;/h2&gt;
&lt;p&gt;我们知道操作系统给每个进程分配虚拟内存，通过页表映射，变成物理内存进行访问。当有了虚拟机之后，情况会变得更加复杂。因为虚拟机对于物理机来讲是一个进程，但是虚拟机里面也有内核，也有虚拟机里面跑的进程。所以有了虚拟机，内存就变成了四类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;虚拟机里面的虚拟内存（Guest OS Virtual Memory，GVA），这是虚拟机里面的进程看到的内存空间；&lt;/li&gt;
&lt;li&gt;虚拟机里面的物理内存（Guest OS Physical Memory，GPA），这是虚拟机里面的操作系统看到的内存，它认为这是物理内存；&lt;/li&gt;
&lt;li&gt;物理机的虚拟内存（Host Virtual Memory，HVA），这是物理机上的 qemu 进程看到的内存空间；&lt;/li&gt;
&lt;li&gt;物理机的物理内存（Host Physical Memory，HPA），这是物理机上的操作系统看到的内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;内存虚拟化的关键在于维护 &lt;code&gt;GPA&lt;/code&gt; 到 &lt;code&gt;HVA&lt;/code&gt; 的映射关系。&lt;/p&gt;
&lt;h2 id=&#34;页面分配和映射的两种方式&#34;&gt;页面分配和映射的两种方式&lt;/h2&gt;
&lt;p&gt;要搞清楚 QEMU system emulation 的仿真架构，首先对于 Host OS，将 QEMU 作为进程启动，然后对于 QEMU 进程，会仿真各种硬件和运行 Guest OS，在这层 OS 上运行要全系统模拟的应用程序，因此对于 Guest OS 管理的内存要实现到 QEMU 进程的虚拟空间的转换需要 softMMU（即需要对 GPA 到 HVA 进行转换）。从 GVA 到 GPA 到 HVA 到 HPA，性能很差，为了解决这个问题，有两种主要的思路。&lt;/p&gt;
&lt;h3 id=&#34;影子页表-shadow-page-tablespt&#34;&gt;影子页表 Shadow Page Table，SPT&lt;/h3&gt;
&lt;p&gt;第一种方式就是软件的方式，影子页表（Shadow Page Table）。&lt;/p&gt;
&lt;p&gt;KVM 通过维护记录 GVA-&amp;gt;HPA 的影子页表 SPT，减少了地址转换带来的开销，可以直接将 GVA 转换为 HPA。&lt;/p&gt;
&lt;p&gt;内存映射要通过页表来管理，页表地址应该放在 CR3 寄存器里面。在软件虚拟化的内存转换中，GVA 到 GPA 的转换通过查询 CR3 寄存器来完成，CR3 中保存了 Guest 的页表基地址，然后载入 MMU 中进行地址转换。&lt;/p&gt;
&lt;p&gt;在加入了 SPT 技术后，当 Guest 访问 CR3 时，KVM 会捕获到这个操作 EXIT_REASON_CR_ACCESS，之后 KVM 会载入特殊的 CR3 和影子页表，欺骗 Guest 这就是真实的 CR3。之后就和传统的访问内存方式一致，当需要访问物理内存的时候，只会经过一层影子页表的转换。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本来的过程是，客户机要通过 cr3 找到客户机的页表，实现从 GVA 到 GPA 的转换，然后在宿主机上，要通过 cr3 找到宿主机的页表，实现从 HVA 到 HPA 的转换。
为了实现客户机虚拟地址空间到宿主机物理地址空间的直接映射。客户机中每个进程都有自己的虚拟地址空间，所以 KVM 需要为客户机中的每个进程页表都要维护一套相应的影子页表。
在客户机访问内存时，使用的不是客户机的原来的页表，而是这个页表对应的影子页表，从而实现了从客户机虚拟地址到宿主机物理地址的直接转换。而且，在 TLB 和 CPU 缓存上缓存的是来自影子页表中客户机虚拟地址和宿主机物理地址之间的映射，也因此提高了缓存的效率。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220124192700.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220124192700.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;为了快速检索 Guest 页表对应的影子页表，KVM 为每个客户机维护了一个 hash 表来进行客户机页表到影子页表之间的映射。对于每一个 Guest 来说，其页目录和页表都有唯一的 GPA，通过页目录/页表的 GPA 就可以在哈希链表中快速地找到对应的影子页目录/页表。&lt;/p&gt;
&lt;p&gt;当 Guest 切换进程时，Guest 会把待切换进程的页表基址载入 CR3，而 KVM 将会截获这一特权指令。KVM 在哈希表中找到与此页表基址对应的影子页表基址，载入 Guest CR3，使 Guest 在恢复运行时 CR3 实际指向的是新切换进程对应的影子页表。&lt;/p&gt;
&lt;p&gt;影子页表的引入，减少了 GVA-&amp;gt;HPA 的转换开销，但是缺点在于需要为 Guest 的每个进程都维护一个影子页表，这将带来很大的内存开销。同时影子页表的建立是很耗时的，如果 Guest 的进程过多，将导致影子页表频繁切换。&lt;/p&gt;
&lt;p&gt;因此 Intel 和 AMD 在此基础上提供了基于硬件的虚拟化技术 EPT。&lt;/p&gt;
&lt;h3 id=&#34;扩展页表-extent-page-tableept&#34;&gt;扩展页表 Extent Page Table，EPT&lt;/h3&gt;
&lt;p&gt;Intel 的 EPT（Extent Page Table）技术和 AMD 的 NPT（Nest Page Table）技术都对内存虚拟化提供了硬件支持。这两种技术原理类似，都是在硬件层面上实现 GVA 到 HPA 之间的转换。下面就以 EPT 为例分析一下 KVM 基于硬件辅助的内存虚拟化实现。&lt;/p&gt;
&lt;p&gt;EPT 在原有客户机页表对客户机虚拟地址 GVA 到客户机物理地址 GPA 映射的基础上，又引入了 EPT 页表来实现客户机物理地址 GPA 到宿主机物理地址 HPA 的另一次映射。客户机运行时，客户机页表被载入 CR3，而 EPT 页表被载入专门的 EPT 页表指针寄存器 EPTP。&lt;/p&gt;
&lt;p&gt;即 EPT 技术采用了在两级页表结构，即原有 Guest OS 页表对 &lt;strong&gt;GVA-&amp;gt;GPA&lt;/strong&gt; 映射的基础上，又引入了 EPT 页表来实现 &lt;strong&gt;GPA-&amp;gt;HPA&lt;/strong&gt; 的另一次映射，这&lt;strong&gt;两次地址映射都是由硬件自动完成&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;有了 EPT，在&lt;strong&gt;GPA-&amp;gt;HPA&lt;/strong&gt;转换的过程中，缺页会产生 EPT 缺页异常。KVM 首先根据引起异常的客户机物理地址，映射到对应的宿主机虚拟地址，然后为此虚拟地址分配新的物理页，最后 KVM 再更新 EPT 页表，建立起引起异常的客户机物理地址到宿主机物理地址之间的映射。&lt;/p&gt;
&lt;p&gt;KVM 只需为每个客户机维护一套 EPT 页表，也大大减少了内存的开销。&lt;/p&gt;
&lt;p&gt;这里，我们重点看第二种方式。因为使用了 EPT 之后，客户机里面的页表映射，也即从 GVA 到 GPA 的转换，还是用传统的方式，和在内存管理那一章讲的没有什么区别。而 EPT 重点帮我们解决的就是从 GPA 到 HPA 的转换问题。因为要经过两次页表，所以 EPT 又 tdp(two dimentional paging)。&lt;/p&gt;
&lt;p&gt;EPT 的页表结构也是分为四层，EPT Pointer（EPTP）指向 PML4 的首地址。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220124194059.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220124194059.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;qemu-的主要工作&#34;&gt;QEMU 的主要工作&lt;/h2&gt;
&lt;p&gt;内存虚拟化的目的就是让虚拟机能够无缝的访问内存。有了 Intel EPT 的支持后，CPU 在 VMX non-root 状态时进行内存访问会再做一次 EPT 转换。在这个过程中，QEMU 会负责以下内容：&lt;/p&gt;
&lt;p&gt;首先需要从自己的进程地址空间中申请内存用于 Guest
需要将上一步中申请到的内存的虚拟地址（HVA）和 Guest 的物理地址之间的映射关系传递给 KVM（kernel），即 GPA-&amp;gt;HVA
需要组织一系列的数据结构来管理虚拟内存空间，并在内存拓扑结构更改时将最新的内存信息同步至 KVM 中&lt;/p&gt;
&lt;h2 id=&#34;qemu-和-kvm-的工作分界&#34;&gt;QEMU 和 KVM 的工作分界&lt;/h2&gt;
&lt;p&gt;QEMU 和 KVM 之间是通过 KVM 提供的 ioctl() 接口进行交互的。在内核的 kvm_vm_ioctl() 中，&lt;strong&gt;设置虚拟机内存&lt;/strong&gt;的系统调用【kernel 就是一系列系统调用函数接口和处理逻辑，其中有个处理”创建/设置虚拟机内存“的系统调用接口】为  &lt;code&gt;VM_SET_USER_MEMORY_REGION&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_vm_ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;KVM_SET_USER_MEMORY_REGION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 在 KVM 中注册用户空间传入的内存信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_userspace_memory_region&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_userspace_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EFAULT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;c1&#34;&gt;// 将传入的数据结构复制到内核空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;copy_from_user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kvm_userspace_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_userspace_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;c1&#34;&gt;// 实际进行处理的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_vm_ioctl_set_memory_region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kvm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kvm_userspace_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到这里需要传递的参数类型为 &lt;code&gt;kvm_userspace_memory_region&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* for KVM_SET_USER_MEMORY_REGION */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_userspace_memory_region&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// slot 编号 [参考：https://www.cnblogs.com/LoyenWang/p/11922887.html]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;// 标志位，例如是否追踪脏页、是否可用等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guest_phys_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Guest 物理地址，即 GPA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;memory_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;// 内存大小，单位 bytes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;userspace_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 从 QEMU 进程地址空间中分配内存的起始地址，即 HVA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;KVM_SET_USER_MEMORY_REGION&lt;/code&gt;这个 &lt;code&gt;ioctl&lt;/code&gt; 主要目的就是设置&lt;code&gt;GPA-&amp;gt;HVA&lt;/code&gt;的映射关系，KVM 会继续调用&lt;code&gt;kvm_vm_ioctl_set_memory_region()&lt;/code&gt;，在内核空间维护并管理 Guest 的内存。&lt;/p&gt;
&lt;h2 id=&#34;相关数据结构&#34;&gt;相关数据结构&lt;/h2&gt;
&lt;h3 id=&#34;addressspace&#34;&gt;AddressSpace&lt;/h3&gt;
&lt;h4 id=&#34;结构体定义&#34;&gt;结构体定义&lt;/h4&gt;
&lt;p&gt;QEMU 用 AddressSpace 结构体表示 Guest 中 CPU/设备看到的内存【也就是Guest OS 可以在 QEMU 进程虚存中用到的所有内存，是 MemoryRegion 的集合，即 GPA 的整体】，类似于物理机中地址空间的概念，但在这里表示的是 Guest 的一段地址空间，如内存地址空间 &lt;code&gt;address_space_memory&lt;/code&gt; 、&lt;code&gt;I/O&lt;/code&gt; 地址空间&lt;code&gt;address_space_io&lt;/code&gt;，它在 QEMU 源码&lt;code&gt;memory.c&lt;/code&gt;中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * struct AddressSpace: describes a mapping of addresses to #MemoryRegion objects
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* private: */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rcu_head&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rcu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Accessed via RCU.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FlatView&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ioeventfd_nb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionIoeventfd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ioeventfds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_ENTRY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address_spaces_link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个 AddressSpace 一般包含一系列的 MemoryRegion：&lt;code&gt;root&lt;/code&gt;指针指向根级 MemoryRegion，而 root 可能有自己的若干个 sub-regions（子节点），于是形成树状结构。这些 MemoryRegion 通过树连接起来，树的根即为 AddressSpace 的 root 域。&lt;/p&gt;
&lt;h4 id=&#34;全局变量&#34;&gt;全局变量&lt;/h4&gt;
&lt;p&gt;另外，QEMU 中有两个全局的静态 AddressSpace，在 memory.c 中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address_space_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 内存地址空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address_space_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;// I/O 地址空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其 root 域分别指向之后会提到的两个 MemoryRegion 类型变量：system_memory、system_io。&lt;/p&gt;
&lt;h3 id=&#34;memoryregion&#34;&gt;MemoryRegion&lt;/h3&gt;
&lt;h4 id=&#34;结构体定义-1&#34;&gt;结构体定义&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;MemoryRegion&lt;/code&gt; 表示在 &lt;code&gt;Guest Memory Layout&lt;/code&gt; 中的一段内存区域【也就是单元级 GPA 的概念，Guest OS 可以管理到的那些 Guest 物理内存单元】，它是联系 &lt;code&gt;GPA&lt;/code&gt; 和 &lt;code&gt;RAMBlocks&lt;/code&gt;（描述真实内存）之间的桥梁，在&lt;code&gt;memory.h&lt;/code&gt;中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* All fields are private - violators will be prosecuted */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionOps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ops&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;// 回调函数集合
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opaque&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// 父 MemoryRegion 指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Int128&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 该区域内存的大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;target_phys_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// 在 Address Space 中的地址，即 HVA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destructor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;             &lt;span class=&#34;c1&#34;&gt;// MemoryRegion 的起始地址，即 GPA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;subpage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;terminates&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;readable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                        &lt;span class=&#34;c1&#34;&gt;// 是否表示 RAM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;readonly&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* For RAM regions */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;enabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                    &lt;span class=&#34;c1&#34;&gt;// 是否已经通知 KVM 使用这段内存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rom_device&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;warning_printed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* For reservations */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alias&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;             &lt;span class=&#34;c1&#34;&gt;// 是否为 MemoryRegion alias
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;target_phys_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;alias_offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 若为 alias，在原 MemoryRegion 中的 offset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;may_overlap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subregions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;subregions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 子区域链表头
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_ENTRY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;subregions_link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 子区域链表节点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;coalesced_ranges&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CoalescedMemoryRange&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;coalesced&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// MemoryRegion 的名字，调试时使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dirty_log_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 表示哪一种 dirty map 被使用，共分三种
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ioeventfd_nb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegionIoeventfd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ioeventfds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;全局变量-1&#34;&gt;全局变量&lt;/h4&gt;
&lt;p&gt;在 QEMU 的 exec.c 中也定义了两个静态的 MemoryRegion 指针变量：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 内存 MemoryRegion，对应 address_space_memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;// I/O MemoryRegion，对应 address_space_io
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与两个全局 AddressSpace 对应，即 AddressSpace 的 root 域指向这两个 MemoryRegion。&lt;/p&gt;
&lt;h4 id=&#34;memoryregion-的类型&#34;&gt;MemoryRegion 的类型&lt;/h4&gt;
&lt;p&gt;MemoryRegion 有多种类型，可以表示一段 RAM、ROM、MMIO、alias(别名)。&lt;/p&gt;
&lt;p&gt;若为 alias 则表示一个 MemoryRegion 的部分区域，例如，QEMU 会为 pc.ram 这个表示 RAM 的 MemoryRegion 添加两个 alias：ram-below-4g 和 ram-above-4g，之后会看到具体的代码实例。&lt;/p&gt;
&lt;p&gt;另外，MemoryRegion 也可以表示一个 container，这就表示它只是其他若干个 MemoryRegion 的容器。&lt;/p&gt;
&lt;p&gt;那么要如何创建不同类型的 &lt;code&gt;MemoryRegion&lt;/code&gt; 呢？&lt;/p&gt;
&lt;p&gt;在 QEMU 中实际上是通过调用不同的初始化函数区分的。根据不同的初始化函数及其功能，可以将 MemoryRegion 划分为以下三种类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根级 MemoryRegion：直接通过 memory_region_init 初始化，没有自己的内存，用于管理 subregion，例如 system_memory：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ops&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;int128_make64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UINT64_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;int128_2_64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subpage&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enabled&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;terminates&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 非实体 MemoryRegion，搜索时会继续前往其 subregions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 根级 MemoryRegion 不分配内存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;readonly&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rom_device&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destructor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;memory_region_destructor_none&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;may_overlap&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subregions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subregions_link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;subregions_link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;coalesced&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_strdup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirty_log_mask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ioeventfd_nb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ioeventfds&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到 mr-&amp;gt;addr 被设置为 0，而 mr-&amp;gt;ram_addr 则并没有初始化。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实体 &lt;code&gt;MemoryRegion&lt;/code&gt;：通过&lt;code&gt;memory_region_init_ram()&lt;/code&gt;初始化，有自己的内存（从 QEMU 进程地址空间中分配），大小为&lt;code&gt;size&lt;/code&gt;，例如&lt;code&gt;ram_memory&lt;/code&gt;、 &lt;code&gt;pci_memory&lt;/code&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pc_memory_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel_cmdline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initrd_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;below_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;above_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rom_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option_rom_mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* ...*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Allocate RAM.  We allocate it as a single memory region and use
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * aliases to address portions of it, mostly for backwards compatibility
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * with older qemus that used qemu_ram_alloc().
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 调用 memory_region_init_ram 对 ram_memory 进行初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init_ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;pc.ram&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;below_4g_mem_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;above_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;vmstate_register_ram_global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_memory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init_ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                            &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                            &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;terminates&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destructor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;memory_region_destructor_ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_ram_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到这里是先调用了&lt;code&gt;memory_region_init()&lt;/code&gt;，之后设置 &lt;code&gt;RAM&lt;/code&gt; 属性，并继续调用&lt;code&gt;qemu_ram_alloc()&lt;/code&gt;分配内存。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;别名 &lt;code&gt;MemoryRegion&lt;/code&gt;：通过&lt;code&gt;memory_region_init_alias()&lt;/code&gt; 初始化，没有自己的内存，表示实体 &lt;code&gt;MemoryRegion&lt;/code&gt; 的一部分。通过 &lt;code&gt;alias&lt;/code&gt; 成员指向实体 &lt;code&gt;MemoryRegion&lt;/code&gt;，&lt;code&gt;alias_offset&lt;/code&gt;为在实体 &lt;code&gt;MemoryRegion&lt;/code&gt; 中的偏移量，例如&lt;code&gt;ram_below_4g&lt;/code&gt;、&lt;code&gt;ram_above_4g&lt;/code&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pc_memory_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel_cmdline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initrd_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;below_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;above_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rom_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_above_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 调用 memory_region_init_alias 对 ram_below_4g 进行初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init_alias&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;ram-below-4g&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;below_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* ..
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init_alias&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;orig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              &lt;span class=&#34;kt&#34;&gt;target_phys_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;orig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 指向实体 MemoryRegion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alias_offset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//通过 offset 得到实体的某一个部分
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ramblock&#34;&gt;RAMBlock&lt;/h3&gt;
&lt;h4 id=&#34;结构体定义-2&#34;&gt;结构体定义&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;MemoryRegion&lt;/code&gt; 用来描述一段逻辑层面上的内存区域，而记录实际分配的内存地址信息的结构体则是 &lt;code&gt;RAMBlock&lt;/code&gt;，在&lt;code&gt;ramblock.h&lt;/code&gt;中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAMBlock&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rcu_head&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rcu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;colo_cache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* For colo, VM&amp;#39;s ram cache */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;used_length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;max_length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resized&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Protected by iothread lock.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;idstr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;256&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* RCU-enabled, writes protected by the ramlist lock */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QLIST_ENTRY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RAMBlock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QLIST_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAMBlockNotifier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ramblock_notifiers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;page_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* dirty bitmap used during migration */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* bitmap of already received pages in postcopy */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;receivedmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * bitmap to track already cleared dirty bitmap.  When the bit is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * set, it means the corresponding memory chunk needs a log-clear.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Set this up to non-NULL to enable the capability to postpone
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * and split clearing of dirty bitmap on the remote node (e.g.,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * KVM).  The bitmap will be set only when doing global sync.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * NOTE: this bitmap is different comparing to the other bitmaps
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * in that one bit can represent multiple guest pages (which is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * decided by the `clear_bmap_shift&amp;#39; variable below).  On
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * destination side, this should always be NULL, and the variable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * `clear_bmap_shift&amp;#39; is meaningless.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;clear_bmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clear_bmap_shift&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * RAM block length that corresponds to the used_length on the migration
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * source (after RAM block sizes were synchronized). Especially, after
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * starting to run the guest, used_length and postcopy_length can differ.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * Used to register/unregister uffd handlers and as the size of the received
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * bitmap. Receiving any page beyond this length will bail out, as it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * could not have been valid on the source.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;postcopy_length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到在 &lt;code&gt;RAMBlock&lt;/code&gt; 中 host 和 offset 域分别对应了 &lt;code&gt;HVA&lt;/code&gt; 和&lt;code&gt;GPA&lt;/code&gt;，因此也可以说 &lt;code&gt;RAMBlock&lt;/code&gt; 中存储了&lt;code&gt;GPA-&amp;gt;HVA&lt;/code&gt;的映射关系，另外每一个 &lt;code&gt;RAMBlock&lt;/code&gt; 都会指向其所属的 &lt;code&gt;MemoryRegion&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id=&#34;全局变量-ram_list&#34;&gt;全局变量 ram_list&lt;/h4&gt;
&lt;p&gt;QEMU 在&lt;code&gt;ramlist.h&lt;/code&gt;中定义了一个全局变量&lt;code&gt;ram_list&lt;/code&gt;，以链表的形式维护了所有的 &lt;code&gt;RAMBlock&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAMList&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;QemuMutex&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mutex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;RAMBlock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mru_block&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* RCU-enabled, writes protected by the ramlist lock. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QLIST_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAMBlock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;blocks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;DirtyMemoryBlocks&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirty_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DIRTY_MEMORY_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QLIST_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAMBlockNotifier&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ramblock_notifiers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAMList&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAMList&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每一个新分配的 &lt;code&gt;RAMBlock&lt;/code&gt; 都会被插入到&lt;code&gt;ram_list&lt;/code&gt;的头部。如需查找地址所对应的 &lt;code&gt;RAMBlock&lt;/code&gt;，则需要遍历&lt;code&gt;ram_list&lt;/code&gt;，当目标地址落在当前&lt;code&gt;RAMBlock&lt;/code&gt;的地址区间时，该 &lt;code&gt;RAMBlock&lt;/code&gt; 即为查找目标。&lt;/p&gt;
&lt;h4 id=&#34;asmrramblock-之间的关系&#34;&gt;AS、MR、RAMBlock 之间的关系&lt;/h4&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220225155936.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220225155936.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;flatview&#34;&gt;FlatView&lt;/h3&gt;
&lt;p&gt;AddressSpace 的 root 域及其子树共同构成了 Guest 的物理地址空间，但这些都是在 QEMU 侧定义的。要传入 KVM 进行设置时，复杂的树状结构是不利于内核进行处理的，因此需要将其&lt;strong&gt;转换为一个“平坦”的地址模&lt;/strong&gt;型，也就是一个从零开始、只包含地址信息的数据结构，这在 QEMU 中通过 &lt;strong&gt;FlatView&lt;/strong&gt; 来表示。每个 AddressSpace 都有一个与之对应的 FlatView 指针 current_map，表示其对应的平面展开视图。&lt;/p&gt;
&lt;h4 id=&#34;结构体定义-3&#34;&gt;结构体定义&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;FlatView&lt;/code&gt; 在&lt;code&gt;memory.c&lt;/code&gt;中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Flattened global view of current active memory hierarchy.  Kept in sorted
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * order.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FlatView&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rcu_head&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rcu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FlatRange&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ranges&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;// 对应的 FlatRange 数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// FlatRange 的数目
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nr_allocated&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 当前数组的项数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AddressSpaceDispatch&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dispatch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，&lt;code&gt;ranges&lt;/code&gt;是一个数组，记录了 &lt;code&gt;FlatView&lt;/code&gt; 下所有的 &lt;code&gt;FlatRange&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id=&#34;flatrange&#34;&gt;FlatRange&lt;/h4&gt;
&lt;p&gt;在 &lt;code&gt;FlatView&lt;/code&gt; 中，&lt;code&gt;FlatRange&lt;/code&gt; 表示在 &lt;code&gt;FlatView&lt;/code&gt; 中的一段内存范围，同样在&lt;code&gt;memory.c&lt;/code&gt;中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Range of memory in the global map.  Addresses are absolute. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FlatRange&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;// 指向所属的 MemoryRegion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;hwaddr&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;offset_in_region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 在全局 MemoryRegion 中的 offset，对应 GPA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;AddrRange&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;             &lt;span class=&#34;c1&#34;&gt;// 代表的地址区间，对应 HVA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dirty_log_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;romd_mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;readonly&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nonvolatile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个 &lt;code&gt;FlatRange&lt;/code&gt; 对应一段虚拟机物理地址区间，各个 &lt;code&gt;FlatRange&lt;/code&gt; 不会重叠，&lt;strong&gt;按照地址的顺序保存在数组中&lt;/strong&gt;，具体的地址范围由一个 &lt;code&gt;AddrRange&lt;/code&gt; 结构来描述：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * AddrRange 用于表示 FlatRange 的起始地址及大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AddrRange&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Int128&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Int128&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;memoryregionsection&#34;&gt;MemoryRegionSection&lt;/h3&gt;
&lt;h4 id=&#34;结构体定义-4&#34;&gt;结构体定义&lt;/h4&gt;
&lt;p&gt;在 &lt;code&gt;QEMU&lt;/code&gt; 中，还有几个起到中介作用的结构体，&lt;code&gt;MemoryRegionSection&lt;/code&gt; 就是其中之一。&lt;/p&gt;
&lt;p&gt;之前介绍的 &lt;code&gt;FlatRange&lt;/code&gt; 代表一个物理地址空间的片段，偏向于描述在 &lt;code&gt;Host&lt;/code&gt; 侧即 &lt;strong&gt;AddressSpace 中的分布【Guest 的物理空间】&lt;/strong&gt;，而 &lt;code&gt;MemoryRegionSection&lt;/code&gt; 则代表在 &lt;code&gt;Guest&lt;/code&gt; 侧即 &lt;strong&gt;MemoryRegion 中的片段&lt;/strong&gt;。&lt;code&gt;MemoryRegionSection&lt;/code&gt; 在&lt;code&gt;memory.h&lt;/code&gt;中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * MemoryRegionSection: describes a fragment of a #MemoryRegion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @mr: the region, or %NULL if empty
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @address_space: the address space the region is mapped in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @offset_within_region: the beginning of the section, relative to @mr&amp;#39;s start
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @size: the size of the section; will not exceed @mr&amp;#39;s boundaries
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @offset_within_address_space: the address of the first byte of the section
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *     relative to the region&amp;#39;s address space
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @readonly: writes to this section are ignored
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;//只是起到描述的作用，描述了是哪个 AddressSpace 的 MemoryRegion，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;//并且在 MemoryRegion 中的 offset，和在 AddressSpace 展开为平坦内存的 offset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                               &lt;span class=&#34;c1&#34;&gt;// 所属的 MemoryRegion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_space&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                    &lt;span class=&#34;c1&#34;&gt;// 关联的 AddressSpace
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;target_phys_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;offset_within_region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 在 MemoryRegion 内部的 offset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                                  &lt;span class=&#34;c1&#34;&gt;// Section 的大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;target_phys_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;offset_within_address_space&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 在 AddressSpace 内部的 offset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;readonly&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                                  &lt;span class=&#34;c1&#34;&gt;// 是否为只读
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;offset_within_region&lt;/code&gt;：在所属 &lt;code&gt;MemoryRegion&lt;/code&gt; 中的&lt;code&gt;offset&lt;/code&gt;。一个&lt;code&gt;AddressSpace&lt;/code&gt; 可能由多个 &lt;code&gt;MemoryRegion&lt;/code&gt; 组成，因此该 &lt;code&gt;offset&lt;/code&gt; 是局部的&lt;/li&gt;
&lt;li&gt;&lt;code&gt;offset_within_address_space&lt;/code&gt;：在所属 &lt;code&gt;AddressSpace&lt;/code&gt; 中的 &lt;code&gt;offset&lt;/code&gt;，它是全局的&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;和其他数据结构之间的关系&#34;&gt;和其他数据结构之间的关系&lt;/h4&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125110422.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125110422.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AddressSpace&lt;/code&gt; 的&lt;code&gt;root&lt;/code&gt;指向对应的根级&lt;code&gt;MemoryRegion&lt;/code&gt;，&lt;code&gt;current_map&lt;/code&gt;指向&lt;code&gt;AddressSpace&lt;/code&gt; 的&lt;code&gt;root&lt;/code&gt;通过&lt;code&gt;generate_memory_topology()&lt;/code&gt;生成的 &lt;code&gt;FlatView&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FlatView&lt;/code&gt; 中的&lt;code&gt;ranges&lt;/code&gt;数组表示该&lt;code&gt;MemoryRegion&lt;/code&gt; 所表示的&lt;code&gt;Guest&lt;/code&gt;地址区间【GPA 的整个平坦物理空间】，并按照地址的顺序进行排列&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MemoryRegionSection&lt;/code&gt; 由&lt;code&gt;ranges&lt;/code&gt;数组中的 &lt;code&gt;FlatRange&lt;/code&gt; 对应生成，作为注册到 &lt;code&gt;KVM&lt;/code&gt;中的基本单位&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;code&gt;QEMU&lt;/code&gt; 在用户空间申请内存后，需要将内存信息通过一系列系统调用传入内核空间的 &lt;code&gt;KVM&lt;/code&gt;，由 &lt;code&gt;KVM&lt;/code&gt; 侧进行管理，因此 &lt;code&gt;QEMU&lt;/code&gt; 侧也定义了一些用于向 &lt;code&gt;KVM&lt;/code&gt; 传递参数的结构体。&lt;/p&gt;
&lt;p&gt;以下为&lt;code&gt;KVM&lt;/code&gt;相关的数据结构。&lt;/p&gt;
&lt;h3 id=&#34;kvmslot&#34;&gt;KVMSlot&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;在 kvm_init.h&lt;/code&gt;中定义，是 &lt;code&gt;KVM&lt;/code&gt; 中内存管理的基本单位：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KVMSlot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;hwaddr&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Guest 物理地址，GPA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;memory_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 内存大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// QEMU 用户空间地址，HVA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Slot 编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 标志位，例如是否追踪脏页、是否可用等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Dirty bitmap cache for the slot */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirty_bmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dirty_bmap_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Cache of the address space ID */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;as_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Cache of the offset in ram address space */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram_start_offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KVMSlot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;KVMSlot&lt;/code&gt; 类似于内存插槽的概念。&lt;/p&gt;
&lt;h3 id=&#34;kvm_userspace_memory_region&#34;&gt;kvm_userspace_memory_region&lt;/h3&gt;
&lt;p&gt;调用&lt;code&gt;ioctl(KVM_SET_USER_MEMORY_REGION)&lt;/code&gt;时需要向 &lt;code&gt;KVM&lt;/code&gt; 传递的参数，在&lt;code&gt;kvm.h&lt;/code&gt;中定义&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* for KVM_SET_USER_MEMORY_REGION */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_userspace_memory_region&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// slot 编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;// 标志位，例如是否追踪脏页、是否可用等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;guest_phys_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Guest 物理地址，GPA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;memory_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;// 内存大小，bytes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;__u64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;userspace_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 从 QEMU 进程空间分配的起始地址，HVA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;memorylistener&#34;&gt;MemoryListener&lt;/h3&gt;
&lt;h4 id=&#34;结构体定义-5&#34;&gt;结构体定义&lt;/h4&gt;
&lt;p&gt;为了监控虚拟机的物理地址访问，对于每一个 &lt;code&gt;AddressSpace&lt;/code&gt;，都会有一个 &lt;code&gt;MemoryListener&lt;/code&gt; 与之对应。每当物理映射&lt;code&gt;GPA-&amp;gt;HVA&lt;/code&gt;发生改变时，就会回调这些函数。&lt;strong&gt;MemoryListener&lt;/strong&gt; 是对一些事件的&lt;strong&gt;回调函数合集&lt;/strong&gt;，在&lt;code&gt;memory.h&lt;/code&gt;中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * MemoryListener: callbacks structure for updates to the physical memory map
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; *
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Allows a component to adjust to changes in the guest-visible memory map.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Use with memory_listener_register() and memory_listener_unregister().
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;begin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;commit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;region_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;region_del&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;region_nop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_stop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_sync&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_global_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_global_stop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;eventfd_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;match_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EventNotifier&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;eventfd_del&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;match_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;EventNotifier&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Lower = earlier (during add), later (during del) */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_space_filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_ENTRY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;全局变量-memory_listeners&#34;&gt;全局变量 memory_listeners&lt;/h4&gt;
&lt;p&gt;所有的 &lt;code&gt;MemoryListener&lt;/code&gt; 都会挂在全局变量&lt;code&gt;memory_listeners&lt;/code&gt;链表上，在&lt;code&gt;memory.c&lt;/code&gt;中定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;QTAILQ_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;memory_listeners&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;QTAILQ_HEAD_INITIALIZER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;memory.c&lt;/code&gt;中枚举了&lt;code&gt;ListenerDirection&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ListenerDirection&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Forward&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Reverse&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;重要数据结构总览&#34;&gt;重要数据结构总览&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;结构体名&lt;/th&gt;
					&lt;th style=&#34;text-align: left&#34;&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;AddressSpace&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;VM 能看到的一段地址空间，偏向 Host 侧【注意指的是偏向】&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;MemoryRegion&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;地址空间中一段逻辑层面的内存区域，偏向 Guest 侧&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;RAMBlock&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;记录实际分配的内存地址信息，存储了 GPA-&amp;gt;HVA 的映射关系&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;FlatView&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;MemoryRegion 对应的平面展开视图，包含一个 FlatRange 类型的 ranges 数组&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;FlatRange&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;对应一段虚拟机物理地址区间，各个 FlatRange 不会重叠，按照地址的顺序保存在数组中&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;MemoryRegionSection&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;表示 MemoryRegion 中的片段&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;MemoryListener&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;回调函数集合&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;KVMSlot&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;KVM 中内存管理的基本单位，表示一个内存插槽&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;kvm_userspace_memory_region&lt;/td&gt;
					&lt;td style=&#34;text-align: left&#34;&gt;调用 ioctl(KVM_SET_USER_MEMORY_REGION) 时需要向 KVM 传递的参数&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;具体实现机制&#34;&gt;具体实现机制&lt;/h2&gt;
&lt;p&gt;QEMU 的内存申请流程大致可分为三个部分：回调函数的注册、AddressSpace 的初始化、实际内存的分配。下面将根据在 vl.c 的 main() 函数中的调用顺序分别介绍。&lt;/p&gt;
&lt;h3 id=&#34;回调函数的注册&#34;&gt;回调函数的注册&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125133808.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125133808.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;configure_accelerator&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;                                     &lt;span class=&#34;c1&#34;&gt;// 初始化 KVM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KVM_CREATE_VM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;                  &lt;span class=&#34;c1&#34;&gt;// 创建 VM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_arch_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;                           &lt;span class=&#34;c1&#34;&gt;// 针对不同的架构进行初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_listener_register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;               &lt;span class=&#34;c1&#34;&gt;// 注册 kvm_memory_listener
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;listener_add_address_space&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 调用 region_add 回调
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_region_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// region_add 对应的回调实现
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_set_phys_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 根据传入的 section 填充 KVMSlot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_set_user_memory_region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                     &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KVM_SET_USER_MEMORY_REGION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进入&lt;code&gt;configure_accelerator()&lt;/code&gt;后，&lt;code&gt;QEMU&lt;/code&gt;会先调用&lt;code&gt;configure_accelerator()&lt;/code&gt;设置 &lt;code&gt;KVM&lt;/code&gt; 的加速支持，之后进入&lt;code&gt;kvm_init()&lt;/code&gt;。该函数主要完成对 KVM 的初始化，包括一些常规检查如 &lt;code&gt;CPU&lt;/code&gt; 个数、&lt;code&gt;KVM&lt;/code&gt; 版本等，之后通过&lt;code&gt;kvm_ioctl(KVM_CREATE_VM)&lt;/code&gt;与内核交互，创建 &lt;code&gt;KVM&lt;/code&gt; 虚拟机。在&lt;code&gt;kvm_init()&lt;/code&gt;的最后，会调用&lt;code&gt;memory_listener_register()&lt;/code&gt;注册&lt;code&gt;kvm_memory_listener&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MachineState&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;MACHINE_GET_CLASS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 打开/dev/kvm
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_open_old&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/dev/kvm&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_RDWR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 创建 VM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KVM_CREATE_VM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EINTR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_arch_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 针对不同的架构进行初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 对于以下 AddressSpace，设置其对应的 listener
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;kvm_memory_listener_register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                 &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_space_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;kvm-memory&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_listener_register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kvm_coalesced_pio_listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_space_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_listener_register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Only one of them can be defined for a listener */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_sync&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_sync_global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_space&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;QTAILQ_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;QTAILQ_LAST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;QTAILQ_INSERT_TAIL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;QTAILQ_FOREACH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;QTAILQ_INSERT_BEFORE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;QTAILQ_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;QTAILQ_LAST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;QTAILQ_INSERT_TAIL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link_as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;QTAILQ_FOREACH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link_as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;priority&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;QTAILQ_INSERT_BEFORE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;other&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link_as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;listener_add_address_space&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后的&lt;code&gt;listener_add_address_space()&lt;/code&gt;主要是将 listener 注册到其对应的 &lt;code&gt;AddressSpace&lt;/code&gt; 上，并根据 &lt;code&gt;AddressSpace&lt;/code&gt; 对应的 &lt;code&gt;FlatRange&lt;/code&gt; 数组，生成 &lt;code&gt;MemoryRegionSection&lt;/code&gt;【&lt;code&gt;MemoryRegionSection&lt;/code&gt;就像是为&lt;code&gt;FlatRange&lt;/code&gt;数组设置的一种中介表示，便于传入&lt;code&gt;KVM&lt;/code&gt;，因为传入&lt;code&gt;KVM&lt;/code&gt;应该是对平坦内存的一种表示】，并注册到 &lt;code&gt;KVM&lt;/code&gt; 中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;listener_add_address_space&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                       &lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FlatView&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FlatRange&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;begin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;begin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* 开启内存脏页记录 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;global_dirty_tracking&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_global_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;log_global_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* 遍历 AddressSpace 对应的 FlatRange 数组，并将其转换成 MemoryRegionSection */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;view&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_get_flatview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;FOR_EACH_FLAT_RANGE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;MemoryRegionSection&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;section&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;section_from_flat_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* 将 section 所代表的内存区域注册到 KVM 中 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;region_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;region_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirty_log_mask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;log_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;log_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dirty_log_mask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;commit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;commit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;flatview_unref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于此时 &lt;code&gt;AddressSapce&lt;/code&gt; 尚未初始化，所以此处的循环为空，仅是在全局注册了&lt;code&gt;kvm_memory_listener&lt;/code&gt;。最后调用了&lt;code&gt;kvm_memory_listener-&amp;gt;region_add()&lt;/code&gt;，对应的实现是&lt;code&gt;kvm_region_add()&lt;/code&gt;，该函数最终会通过&lt;code&gt;ioctl(KVM_SET_USER_MEMORY_REGION)&lt;/code&gt;，将 &lt;code&gt;QEMU&lt;/code&gt; 侧申请的内存信息传入 &lt;code&gt;KVM&lt;/code&gt; 进行注册，这里的流程会在下一部分进行分析。&lt;/p&gt;
&lt;h3 id=&#34;addressspace-的初始化&#34;&gt;AddressSpace 的初始化&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125154841.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125154841.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;cpu_exec_init_all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_map_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 初始化 system_memory/io 这两个全局 MemoryRegion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;set_system_memory_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// address_space_memory-&amp;gt;root = system_memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_update_topology&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 为 MemoryRegion 生成 FlatView
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;         &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_update_topology&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// as-&amp;gt;current_map = new_view
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;              &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_update_topology_pass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;                   &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_region_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// region_add 对应的回调实现
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;                        &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_set_phys_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 根据传入的 section 填充 KVMSlot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;                             &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_set_user_memory_region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;                                  &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KVM_SET_USER_MEMORY_REGION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_listener_register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 注册对应的 MemoryListener
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;         &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;listener_add_address_space&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;io_mem_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// ram/rom/unassigned/notdirty/subpage-ram/watch
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一部分在全局注册了&lt;code&gt;kvm_memory_listener&lt;/code&gt;，但由于&lt;code&gt;AddressSpace&lt;/code&gt; 尚未初始化，实际上并未向 &lt;code&gt;KVM&lt;/code&gt; 中注册任何实际的内存信息。&lt;code&gt;QEMU&lt;/code&gt; 在&lt;code&gt;main()&lt;/code&gt;函数中会继续调用&lt;code&gt;cpu_exec_init_all()&lt;/code&gt;对&lt;code&gt;AddressSpace&lt;/code&gt;进行初始化，该函数实际上是对两个 &lt;code&gt;init&lt;/code&gt; 函数的封装调用：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;cpu_exec_init_all&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;qemu_mutex_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mutex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* The data structures we set up here depend on knowing the page size,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * so no more changes can be made after this point.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * In an ideal world, nothing we did before we had finished the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * machine setup would care about the target page size, and we could
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * do this much later, rather than requiring board models to state
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * up front what their requirements are.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;finalize_target_page_bits&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;io_mem_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;// 初始化六个I/O MemoryRegion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_map_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 初始化两个全局 AddressSpace，以及对应的 MemoryRegion、FlatView
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;qemu_mutex_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map_client_list_lock&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;先来看&lt;code&gt;memory_map_init()&lt;/code&gt;，主要用来初始化两个全局的系统地址空间&lt;code&gt;system_memory&lt;/code&gt;、&lt;code&gt;system_io&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_map_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 1. 初始化 system_memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;system&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UINT64_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 2. 设置 address_space_memory 关联 system_memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 这两个都是全局变量，也就是把内存地址空间和 IO 地址空间于对应的 MemoryRegion 联系起来 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//及其对应的 FlatView
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;address_space_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_space_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;memory&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;system_io&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 1. 初始化 system_io  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unassigned_io_ops&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;io&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                          &lt;span class=&#34;mi&#34;&gt;65536&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 2. 设置 address_space_io 关联 system_io 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 及其对应的 FlatView
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;address_space_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_space_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;I/O&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里比较重要的是&lt;code&gt;address_space_init()&lt;/code&gt;，先设置 &lt;code&gt;AddressSpace&lt;/code&gt; 对应的 &lt;code&gt;MemoryRegion&lt;/code&gt;，之后根据&lt;code&gt;system_memory&lt;/code&gt;更新&lt;code&gt;address_space_memory&lt;/code&gt;对应的 &lt;code&gt;FlatView&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 将 address_space_memory 的 root 域指向 system_memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current_map&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ioeventfd_nb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ioeventfds&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_INSERT_TAIL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address_spaces&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;address_spaces_link&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_strdup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;anonymous&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 根据 system_memory 更新 address_space_memory 对应的 FlatView
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;address_space_update_topology&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;address_space_update_ioeventfds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;address_space_update_topology()&lt;/code&gt;会继续调用&lt;code&gt;generate_memory_topology()&lt;/code&gt;生成 &lt;code&gt;AddressSpace&lt;/code&gt; 对应的 &lt;code&gt;FlatView&lt;/code&gt;视图：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_update_topology&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physmr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_get_flatview_root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;flatviews_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;g_hash_table_lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flat_views&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;physmr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;generate_memory_topology&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physmr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;address_space_set_flatview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;address_space_update_topology()&lt;/code&gt;会先调用&lt;code&gt;generate_memory_topology()&lt;/code&gt;生成&lt;code&gt;system_memory&lt;/code&gt;更新后的视图&lt;code&gt;new_view&lt;/code&gt;，再将&lt;code&gt;address_space_memory&lt;/code&gt;的&lt;code&gt;current_map&lt;/code&gt;指向这个&lt;code&gt;new_view&lt;/code&gt;，最后销毁&lt;code&gt;old_view&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_set_flatview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AddressSpace&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FlatView&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_to_flatview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;physmr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_get_flatview_root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FlatView&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_view&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_hash_table_lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flat_views&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;physmr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;flatview_ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;flatview_ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;QTAILQ_EMPTY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listeners&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;FlatView&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tmpview&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;old_view2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tmpview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;address_space_update_topology_pass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;old_view2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;address_space_update_topology_pass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;old_view2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Writes are protected by the BQL.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;qatomic_rcu_set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;flatview_unref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Note that all the old MemoryRegions are still alive up to this
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * point.  This relieves most MemoryListeners from the need to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * ref/unref the MemoryRegions they get---unless they use them
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * outside the iothread mutex, in which case precise reference
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * counting is necessary.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;flatview_unref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_view&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;address_space_update_topology_pass()&lt;/code&gt;的最后，会调用&lt;code&gt;MEMORY_LISTENER_UPDATE_REGION&lt;/code&gt;这个宏，触发&lt;code&gt;region_add&lt;/code&gt;对应的回调函数&lt;code&gt;kvm_region_add()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这个宏在&lt;code&gt;memory.c&lt;/code&gt;中定义，会将 &lt;code&gt;FlatView&lt;/code&gt; 中的 &lt;code&gt;FlatRange&lt;/code&gt; 转换为 &lt;code&gt;MemoryRegionSection&lt;/code&gt;，作为入参传递给&lt;code&gt;kvm_region_add()&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* No need to ref/unref .mr, the FlatRange keeps it alive.  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...)  \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    do {                                                                \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MemoryRegionSection mrs = section_from_flat_range(fr,           \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;                address_space_to_flatview(as));                         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MEMORY_LISTENER_CALL(as, callback, dir, &amp;amp;mrs, ##_args);         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    } while(0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而&lt;code&gt;kvm_region_add()&lt;/code&gt;实际上是对&lt;code&gt;kvm_set_phys_mem()&lt;/code&gt;的封装调用。该函数比较复杂，会根据传入的&lt;code&gt;section&lt;/code&gt;填充 KVMSlot，再传递给&lt;code&gt;kvm_set_user_memory_region()&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_set_user_memory_region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KVMMemoryListener&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kml&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KVMSlot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;KVMState&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_userspace_memory_region&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 根据 KVMSlot 填充 kvm_userspace_memory_region
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kml&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;as_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;guest_phys_addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;userspace_addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;^&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KVM_MEM_READONLY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Set the slot size to 0 before setting the slot to the desired
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;         * value. This is needed based on KVM commit 75d61fbc. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_vm_ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KVM_SET_USER_MEMORY_REGION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;memory_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_vm_ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KVM_SET_USER_MEMORY_REGION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;slot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到这里又将 &lt;code&gt;KVMSlot&lt;/code&gt; 转换为 &lt;code&gt;kvm_userspace_memory_region&lt;/code&gt;，作为&lt;code&gt;ioctl()&lt;/code&gt;的参数，交给内核中的 &lt;code&gt;KVM&lt;/code&gt; 进行内存的注册【设置&lt;code&gt;GPA-&amp;gt;HVA&lt;/code&gt;的映射关系，在内核空间维护并管理 Guest 的内存】。&lt;/p&gt;
&lt;p&gt;至此 QEMU 侧负责管理内存的数据结构均已完成初始化，&lt;strong&gt;可以参考下面的图片了解各数据结构之间的对应关系&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127155506.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127155506.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;实际内存的分配&#34;&gt;实际内存的分配&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127160121.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127160121.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;machine&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pc_init_pci&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 初始化虚拟机
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pc_init1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system_io&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pci_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;pci&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// pci_memory, rom_memory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;pc_memory_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 初始化内存，分配实际的物理内存地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init_ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 创建 pc.ram, pc.rom 并分配内存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_ram_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;         &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_ram_alloc_from_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;vmstate_register_ram_global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 MR 的 name 写入 RAMBlock 的 idstr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;vmstate_register_ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;         &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_ram_set_idstr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;err&#34;&gt;├─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init_alias&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 初始化 ram_below_4g, ram_above_4g
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_add_subregion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 在 system_memory 中添加 subregions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_add_subregion_common&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_update_topology&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 为 MemoryRegion 生成 FlatView
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                     &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_update_topology&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// as-&amp;gt;current_map = new_view
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                          &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;address_space_update_topology_pass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                               &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_region_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// region_add 对应的回调实现
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                    &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_set_phys_mem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 根据传入的 section 填充 KVMSlot
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                         &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_set_user_memory_region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                                              &lt;span class=&#34;err&#34;&gt;└─&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KVM_SET_USER_MEMORY_REGION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之前的回调函数注册、AddressSpace 的初始化，实际上均没有对应的物理内存。【实际的内存是在 RAMBlock 中】&lt;/p&gt;
&lt;p&gt;我们再回到 &lt;code&gt;qemu&lt;/code&gt; 启动的 &lt;code&gt;main&lt;/code&gt; 函数中。接下来的初始化过程会调用 &lt;code&gt;pc_init1&lt;/code&gt;。在这里面，对于 &lt;code&gt;CPU&lt;/code&gt; 虚拟化，我们会调用 &lt;code&gt;pc_cpus_init&lt;/code&gt;。另外，&lt;code&gt;pc_init1&lt;/code&gt; 还会调用&lt;code&gt;pc_memory_init&lt;/code&gt;，进行内存的虚拟化。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pc_memory_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kernel_cmdline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initrd_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;below_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;above_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rom_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;option_rom_mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;// 两个实体 MR: pc.ram, pc.rom
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_above_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 两个别名 MR: ram_below_4g, ram_above_4g
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Allocate RAM.  We allocate it as a single memory region and use
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * aliases to address portions of it, mostly for backwards compatibility
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * with older qemus that used qemu_ram_alloc().
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 创建 ram
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 分配具体的内存（实际上会创建一个 RAMBlock 并将其 offset 值写入 ram.ram_addr，对应 GPA）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init_ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;pc.ram&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;below_4g_mem_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;above_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 将 MR 的 name 写入 RAMBlock 的 idstr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;vmstate_register_ram_global&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_memory&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 创建 ram_below_4g 表示 4G 以下的内存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init_alias&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;ram-below-4g&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;below_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 将 ram_below_4g 挂在 system_memory 下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_add_subregion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram_below_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;above_4g_mem_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;ram_above_4g&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_above_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;memory_region_init_alias&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_above_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;ram-above-4g&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;below_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;above_4g_mem_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;memory_region_add_subregion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x100000000ULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ram_above_4g&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的重点在于&lt;code&gt;memory_region_init_ram()&lt;/code&gt;，它通过&lt;code&gt;qemu_ram_alloc()&lt;/code&gt;获取 ram 这个 &lt;code&gt;MemoryRegion&lt;/code&gt; 对应的 &lt;code&gt;RAMBlock&lt;/code&gt; 的&lt;code&gt;offset&lt;/code&gt;，并存入&lt;code&gt;ram.ram_addr&lt;/code&gt;，这样就可以在&lt;code&gt;ram_list&lt;/code&gt;中根据该字段查找 &lt;code&gt;MR&lt;/code&gt; 对应的 &lt;code&gt;RAMBlock&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;memory_region_init_ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;uint64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memory_region_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 填充字段，初始化默认值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 表示为 RAM
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;terminates&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 表示为实体 MemoryRegion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destructor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;memory_region_destructor_ram&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_addr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_ram_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 这里保存 RAMBlock 的 offset，即 GPA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而 qemu_ram_alloc() 最终会调用 qemu_ram_alloc_from_ptr()，创建一个对应大小 RAMBlock 并分配内存，返回对应的 GPA 地址存入 mr-&amp;gt;ram_addr 中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_ram_alloc_from_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;ram_addr_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                   &lt;span class=&#34;n&#34;&gt;MemoryRegion&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;RAMBlock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 创建一个 RAMBlock
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;TARGET_PAGE_ALIGN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 页对齐
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 初始化 new_block
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 new_block-&amp;gt; 指向入参的 MemoryRegion
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;find_ram_offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 从 ram_list 中的 RAMBlock 之间找到一段可以满足 size 需求的 gap，并返回起始地址的 offset，对应 GPA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 新建的 RAMBlock host 字段为空，跳过
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RAM_PREALLOC_MASK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mem_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 未指定 mem_path
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#if defined (__linux__) &amp;amp;&amp;amp; !defined(TARGET_S390X)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;file_ram_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mem_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_vmalloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nf&#34;&gt;qemu_madvise&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QEMU_MADV_MERGEABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;-mem-path option unsupported&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;xen_enabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nf&#34;&gt;xen_ram_alloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;kvm_enabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 从这里继续
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;cm&#34;&gt;/* some s390/kvm configurations have special constraints */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_vmalloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 实际上还是调用 qemu_vmalloc(size)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_vmalloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 从 QEMU 的线性空间中分配 size 大小的内存，返回 HVA
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;qemu_madvise&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QEMU_MADV_MERGEABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 length 设置为 size
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QLIST_INSERT_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blocks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将该 RAMBlock 插入 ram_list 头部
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ram_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;phys_dirty&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_realloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;phys_dirty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 重新分配 ram_list.phys_dirty 的内存空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                       &lt;span class=&#34;nf&#34;&gt;last_ram_offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TARGET_PAGE_BITS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;memset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ram_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;phys_dirty&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TARGET_PAGE_BITS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TARGET_PAGE_BITS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;cpu_physical_memory_set_dirty_range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 对该 RAMBlock 对应的内存标记为 dirty
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;qemu_ram_setup_dump&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;kvm_enabled&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;kvm_setup_guest_memory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_block&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样一来&lt;code&gt;ram&lt;/code&gt;【其实就是&lt;code&gt;system memory&lt;/code&gt;，整个&lt;code&gt;Guest&lt;/code&gt;物理空间的大小】对应的 &lt;code&gt;RAMBlock&lt;/code&gt; 中就分配好了 &lt;code&gt;GPA&lt;/code&gt; 和 &lt;code&gt;HVA&lt;/code&gt;，就可以&lt;strong&gt;将内存信息同步至 KVM 侧&lt;/strong&gt;了。&lt;/p&gt;
&lt;p&gt;最后回到&lt;code&gt;pc_memory_init()&lt;/code&gt;中，在分配完实际内存后，会先调用&lt;code&gt;memory_region_init_alias()&lt;/code&gt;初始化&lt;code&gt;ram_below_4g&lt;/code&gt;、&lt;code&gt;ram_above_4g&lt;/code&gt;这两个&lt;code&gt;alias&lt;/code&gt;，之后调用&lt;code&gt;memory_region_add_subregion()&lt;/code&gt;将这两个 &lt;code&gt;alias&lt;/code&gt; 指向&lt;code&gt;ram&lt;/code&gt;这个实体 &lt;code&gt;MemoryRegion&lt;/code&gt;。如下图，该函数最终会触发&lt;code&gt;kvm_region_add()&lt;/code&gt;回调，将实际的内存信息传入 &lt;code&gt;KVM&lt;/code&gt; 注册。该过程如下图所示，与之前分析的流程相同，此处不再赘述。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127163205.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127163205.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;虚拟机的内存管理也是需要用户态的 &lt;code&gt;qemu&lt;/code&gt; 和内核态的 &lt;code&gt;KVM&lt;/code&gt; 共同完成。为了加速内存映射，需要借助硬件的 &lt;code&gt;EPT&lt;/code&gt; 技术。&lt;/p&gt;
&lt;h3 id=&#34;qemu-侧&#34;&gt;QEMU 侧&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;创建一系列 &lt;code&gt;MemoryRegion&lt;/code&gt;，分别表示 &lt;code&gt;Guest&lt;/code&gt; 中的 &lt;code&gt;RAM&lt;/code&gt;、&lt;code&gt;ROM&lt;/code&gt; 等区域。&lt;code&gt;MemoryRegion&lt;/code&gt;之间通过 &lt;code&gt;alias&lt;/code&gt; 或 &lt;code&gt;subregions&lt;/code&gt; 的方式维护相互之间的关系，从而进一步细化区域的定义&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于一个实体 &lt;code&gt;MemoryRegion&lt;/code&gt;（非 &lt;code&gt;alias&lt;/code&gt;），在初始化内存的过程中 &lt;code&gt;QEMU&lt;/code&gt; 会创建它所对应的 &lt;code&gt;RAMBlock&lt;/code&gt;。该 &lt;code&gt;RAMBlock&lt;/code&gt; 通过调用&lt;code&gt;qemu_ram_alloc_from_ptr()&lt;/code&gt;从 &lt;code&gt;QEMU&lt;/code&gt; 的进程地址空间中&lt;strong&gt;以 mmap 的方式分配内存&lt;/strong&gt;，并负责&lt;strong&gt;维护该 MemoryRegion 对应内存的起始 GPA/HVA/size 等相关信息&lt;/strong&gt;【在&lt;code&gt;qemu_ram_alloc_from_ptr&lt;/code&gt;中创建的新&lt;code&gt;RAMBlock&lt;/code&gt;有&lt;code&gt;offset&lt;/code&gt;、&lt;code&gt;host&lt;/code&gt;的赋值，即&lt;code&gt;GPA-&amp;gt;HVA&lt;/code&gt;的对应关系】&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;AddressSpace&lt;/code&gt; 表示 &lt;code&gt;Guest&lt;/code&gt; 的物理地址空间。如果 &lt;code&gt;AddressSpace&lt;/code&gt; 中的 &lt;code&gt;MemoryRegion&lt;/code&gt; 发生变化，则注册的 &lt;code&gt;listener&lt;/code&gt; 会被触发，将所属的 &lt;code&gt;MemoryRegion&lt;/code&gt; 树展开生成一维的 &lt;code&gt;FlatView&lt;/code&gt;，比较 FlatRange 是否发生了变化。如果是，则调用相应的方法对 &lt;code&gt;MemoryRegionSection&lt;/code&gt; 进行检查，更新 &lt;code&gt;QEMU&lt;/code&gt; 中的 &lt;code&gt;KVMSlot&lt;/code&gt;，同时填充&lt;code&gt;kvm_userspace_memory_region&lt;/code&gt;结构体，作为&lt;code&gt;ioctl()&lt;/code&gt;的参数更新 &lt;code&gt;KVM&lt;/code&gt; 中的&lt;code&gt;kvm_memory_slot&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;kvm-侧&#34;&gt;KVM 侧&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;当 &lt;code&gt;QEMU&lt;/code&gt; 通过&lt;code&gt;ioctl()&lt;/code&gt;创建 &lt;code&gt;vcpu&lt;/code&gt; 时，调用&lt;code&gt;kvm_mmu_create()&lt;/code&gt;初始化 &lt;code&gt;MMU&lt;/code&gt; 相关信息。
当 &lt;code&gt;KVM&lt;/code&gt; 要进入 &lt;code&gt;Guest&lt;/code&gt; 前，&lt;code&gt;vcpu_enter_guest()=&amp;gt;kvm_mmu_reload()&lt;/code&gt;会将根级页表地址加载到 &lt;code&gt;VMCS&lt;/code&gt;，让 &lt;code&gt;Guest&lt;/code&gt; 使用该页表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当发生&lt;code&gt;EPT Violation&lt;/code&gt; 时，&lt;code&gt;VM-EXIT&lt;/code&gt;到 &lt;code&gt;KVM&lt;/code&gt; 中。如果是缺页，则根据 &lt;code&gt;GPA&lt;/code&gt; 算出 &lt;code&gt;gfn&lt;/code&gt;，再根据 &lt;code&gt;gfn&lt;/code&gt; 找到对应的 &lt;code&gt;KVMSlot&lt;/code&gt;，从中得到对应的 &lt;code&gt;HVA&lt;/code&gt;。然后根据 &lt;code&gt;HVA&lt;/code&gt; 算出对应的 &lt;code&gt;pfn&lt;/code&gt;，确保该 &lt;code&gt;Page&lt;/code&gt; 位于内存中。填好缺失的页之后，需要更新 &lt;code&gt;EPT&lt;/code&gt;，完善其中缺少的页表项，逐层补全页表&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127163418.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127163418.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;虚拟机的物理内存空间里面的页面当然不是一开始就映射到物理页面的，只有当虚拟机的内存被访问的时候，也即 &lt;code&gt;mmap&lt;/code&gt; 分配的虚拟内存空间被访问的时候，先查看 &lt;code&gt;EPT&lt;/code&gt; 页表，是否已经映射过，如果已经映射过，则经过四级页表映射，就能访问到物理页面。
如果没有映射过，则虚拟机会通过&lt;code&gt;VM-Exit&lt;/code&gt;指令回到宿主机模式，通过 &lt;code&gt;handle_ept_violation&lt;/code&gt; 补充页表映射。先是通过 &lt;code&gt;handle_mm_fault&lt;/code&gt;为虚拟机的物理内存空间分配真正的物理页面，然后通过 &lt;code&gt;__direct_map&lt;/code&gt; 添加 &lt;code&gt;EPT&lt;/code&gt; 页表映射。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127171031.jpg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127171031.jpg&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;http://xudaxian.fun/2020/09/03/QEMU%E5%86%85%E5%AD%98%E7%A9%BA%E9%97%B4%E8%99%9A%E6%8B%9F%E5%8C%96%E5%8F%8A%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/&#34;&gt;“QEMU 内存空间虚拟化及内存管理” - B10g | FΓom 许大仙&lt;/a&gt;
&lt;a href=&#34;https://www.cnblogs.com/LoyenWang/p/13943005.html&#34;&gt;【原创】Linux 虚拟化 KVM-Qemu 分析（五）之内存虚拟化 - LoyenWang - 博客园&lt;/a&gt;
&lt;a href=&#34;https://blog.csdn.net/xiongwenwu/article/details/58586013&#34;&gt;KVM/Qemu 工作原理系列目录_xiongwenwu 的专栏-CSDN 博客_qemu 目录结构&lt;/a&gt;
&lt;a href=&#34;https://abelsu7.top/2019/07/07/kvm-memory-virtualization/&#34;&gt;QEMU 内存虚拟化源码分析 | Keep Coding | 苏易北&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<blockquote>
<p>1.大部分转载自<a href="https://abelsu7.top/2019/07/07/kvm-memory-virtualization/">QEMU 内存虚拟化源码分析 | Keep Coding | 苏易北</a>
2.原文源码为 QEMU1.2.0，版本较旧，部分源码内容根据 QEMU6.2 版本修改
3.部分内容根据自己理解补充添加</p>
</blockquote>
<h2 id="概述">概述</h2>
<p>我们知道操作系统给每个进程分配虚拟内存，通过页表映射，变成物理内存进行访问。当有了虚拟机之后，情况会变得更加复杂。因为虚拟机对于物理机来讲是一个进程，但是虚拟机里面也有内核，也有虚拟机里面跑的进程。所以有了虚拟机，内存就变成了四类：</p>
<ul>
<li>虚拟机里面的虚拟内存（Guest OS Virtual Memory，GVA），这是虚拟机里面的进程看到的内存空间；</li>
<li>虚拟机里面的物理内存（Guest OS Physical Memory，GPA），这是虚拟机里面的操作系统看到的内存，它认为这是物理内存；</li>
<li>物理机的虚拟内存（Host Virtual Memory，HVA），这是物理机上的 qemu 进程看到的内存空间；</li>
<li>物理机的物理内存（Host Physical Memory，HPA），这是物理机上的操作系统看到的内存。</li>
</ul>
<p>内存虚拟化的关键在于维护 <code>GPA</code> 到 <code>HVA</code> 的映射关系。</p>
<h2 id="页面分配和映射的两种方式">页面分配和映射的两种方式</h2>
<p>要搞清楚 QEMU system emulation 的仿真架构，首先对于 Host OS，将 QEMU 作为进程启动，然后对于 QEMU 进程，会仿真各种硬件和运行 Guest OS，在这层 OS 上运行要全系统模拟的应用程序，因此对于 Guest OS 管理的内存要实现到 QEMU 进程的虚拟空间的转换需要 softMMU（即需要对 GPA 到 HVA 进行转换）。从 GVA 到 GPA 到 HVA 到 HPA，性能很差，为了解决这个问题，有两种主要的思路。</p>
<h3 id="影子页表-shadow-page-tablespt">影子页表 Shadow Page Table，SPT</h3>
<p>第一种方式就是软件的方式，影子页表（Shadow Page Table）。</p>
<p>KVM 通过维护记录 GVA-&gt;HPA 的影子页表 SPT，减少了地址转换带来的开销，可以直接将 GVA 转换为 HPA。</p>
<p>内存映射要通过页表来管理，页表地址应该放在 CR3 寄存器里面。在软件虚拟化的内存转换中，GVA 到 GPA 的转换通过查询 CR3 寄存器来完成，CR3 中保存了 Guest 的页表基地址，然后载入 MMU 中进行地址转换。</p>
<p>在加入了 SPT 技术后，当 Guest 访问 CR3 时，KVM 会捕获到这个操作 EXIT_REASON_CR_ACCESS，之后 KVM 会载入特殊的 CR3 和影子页表，欺骗 Guest 这就是真实的 CR3。之后就和传统的访问内存方式一致，当需要访问物理内存的时候，只会经过一层影子页表的转换。</p>
<blockquote>
<p>本来的过程是，客户机要通过 cr3 找到客户机的页表，实现从 GVA 到 GPA 的转换，然后在宿主机上，要通过 cr3 找到宿主机的页表，实现从 HVA 到 HPA 的转换。
为了实现客户机虚拟地址空间到宿主机物理地址空间的直接映射。客户机中每个进程都有自己的虚拟地址空间，所以 KVM 需要为客户机中的每个进程页表都要维护一套相应的影子页表。
在客户机访问内存时，使用的不是客户机的原来的页表，而是这个页表对应的影子页表，从而实现了从客户机虚拟地址到宿主机物理地址的直接转换。而且，在 TLB 和 CPU 缓存上缓存的是来自影子页表中客户机虚拟地址和宿主机物理地址之间的映射，也因此提高了缓存的效率。</p>
</blockquote>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220124192700.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220124192700.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>为了快速检索 Guest 页表对应的影子页表，KVM 为每个客户机维护了一个 hash 表来进行客户机页表到影子页表之间的映射。对于每一个 Guest 来说，其页目录和页表都有唯一的 GPA，通过页目录/页表的 GPA 就可以在哈希链表中快速地找到对应的影子页目录/页表。</p>
<p>当 Guest 切换进程时，Guest 会把待切换进程的页表基址载入 CR3，而 KVM 将会截获这一特权指令。KVM 在哈希表中找到与此页表基址对应的影子页表基址，载入 Guest CR3，使 Guest 在恢复运行时 CR3 实际指向的是新切换进程对应的影子页表。</p>
<p>影子页表的引入，减少了 GVA-&gt;HPA 的转换开销，但是缺点在于需要为 Guest 的每个进程都维护一个影子页表，这将带来很大的内存开销。同时影子页表的建立是很耗时的，如果 Guest 的进程过多，将导致影子页表频繁切换。</p>
<p>因此 Intel 和 AMD 在此基础上提供了基于硬件的虚拟化技术 EPT。</p>
<h3 id="扩展页表-extent-page-tableept">扩展页表 Extent Page Table，EPT</h3>
<p>Intel 的 EPT（Extent Page Table）技术和 AMD 的 NPT（Nest Page Table）技术都对内存虚拟化提供了硬件支持。这两种技术原理类似，都是在硬件层面上实现 GVA 到 HPA 之间的转换。下面就以 EPT 为例分析一下 KVM 基于硬件辅助的内存虚拟化实现。</p>
<p>EPT 在原有客户机页表对客户机虚拟地址 GVA 到客户机物理地址 GPA 映射的基础上，又引入了 EPT 页表来实现客户机物理地址 GPA 到宿主机物理地址 HPA 的另一次映射。客户机运行时，客户机页表被载入 CR3，而 EPT 页表被载入专门的 EPT 页表指针寄存器 EPTP。</p>
<p>即 EPT 技术采用了在两级页表结构，即原有 Guest OS 页表对 <strong>GVA-&gt;GPA</strong> 映射的基础上，又引入了 EPT 页表来实现 <strong>GPA-&gt;HPA</strong> 的另一次映射，这<strong>两次地址映射都是由硬件自动完成</strong>。</p>
<p>有了 EPT，在<strong>GPA-&gt;HPA</strong>转换的过程中，缺页会产生 EPT 缺页异常。KVM 首先根据引起异常的客户机物理地址，映射到对应的宿主机虚拟地址，然后为此虚拟地址分配新的物理页，最后 KVM 再更新 EPT 页表，建立起引起异常的客户机物理地址到宿主机物理地址之间的映射。</p>
<p>KVM 只需为每个客户机维护一套 EPT 页表，也大大减少了内存的开销。</p>
<p>这里，我们重点看第二种方式。因为使用了 EPT 之后，客户机里面的页表映射，也即从 GVA 到 GPA 的转换，还是用传统的方式，和在内存管理那一章讲的没有什么区别。而 EPT 重点帮我们解决的就是从 GPA 到 HPA 的转换问题。因为要经过两次页表，所以 EPT 又 tdp(two dimentional paging)。</p>
<p>EPT 的页表结构也是分为四层，EPT Pointer（EPTP）指向 PML4 的首地址。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220124194059.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220124194059.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="qemu-的主要工作">QEMU 的主要工作</h2>
<p>内存虚拟化的目的就是让虚拟机能够无缝的访问内存。有了 Intel EPT 的支持后，CPU 在 VMX non-root 状态时进行内存访问会再做一次 EPT 转换。在这个过程中，QEMU 会负责以下内容：</p>
<p>首先需要从自己的进程地址空间中申请内存用于 Guest
需要将上一步中申请到的内存的虚拟地址（HVA）和 Guest 的物理地址之间的映射关系传递给 KVM（kernel），即 GPA-&gt;HVA
需要组织一系列的数据结构来管理虚拟内存空间，并在内存拓扑结构更改时将最新的内存信息同步至 KVM 中</p>
<h2 id="qemu-和-kvm-的工作分界">QEMU 和 KVM 的工作分界</h2>
<p>QEMU 和 KVM 之间是通过 KVM 提供的 ioctl() 接口进行交互的。在内核的 kvm_vm_ioctl() 中，<strong>设置虚拟机内存</strong>的系统调用【kernel 就是一系列系统调用函数接口和处理逻辑，其中有个处理”创建/设置虚拟机内存“的系统调用接口】为  <code>VM_SET_USER_MEMORY_REGION</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">long</span> <span class="nf">kvm_vm_ioctl</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">filp</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">               <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">ioctl</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">arg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* ... */</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">KVM_SET_USER_MEMORY_REGION</span><span class="p">:</span> <span class="p">{</span> <span class="c1">// 在 KVM 中注册用户空间传入的内存信息
</span></span></span><span class="line"><span class="cl">        <span class="k">struct</span> <span class="n">kvm_userspace_memory_region</span> <span class="n">kvm_userspace_mem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">r</span> <span class="o">=</span> <span class="o">-</span><span class="n">EFAULT</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="c1">// 将传入的数据结构复制到内核空间
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">copy_from_user</span><span class="p">(</span><span class="o">&amp;</span><span class="n">kvm_userspace_mem</span><span class="p">,</span> <span class="n">argp</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">kvm_userspace_mem</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">         <span class="c1">// 实际进行处理的函数
</span></span></span><span class="line"><span class="cl">        <span class="n">r</span> <span class="o">=</span> <span class="nf">kvm_vm_ioctl_set_memory_region</span><span class="p">(</span><span class="n">kvm</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">kvm_userspace_mem</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">r</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* ... */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>可以看到这里需要传递的参数类型为 <code>kvm_userspace_memory_region</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* for KVM_SET_USER_MEMORY_REGION */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">kvm_userspace_memory_region</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">__u32</span> <span class="n">slot</span><span class="p">;</span>            <span class="c1">// slot 编号 [参考：https://www.cnblogs.com/LoyenWang/p/11922887.html]
</span></span></span><span class="line"><span class="cl">    <span class="n">__u32</span> <span class="n">flags</span><span class="p">;</span>           <span class="c1">// 标志位，例如是否追踪脏页、是否可用等
</span></span></span><span class="line"><span class="cl">    <span class="n">__u64</span> <span class="n">guest_phys_addr</span><span class="p">;</span> <span class="c1">// Guest 物理地址，即 GPA
</span></span></span><span class="line"><span class="cl">    <span class="n">__u64</span> <span class="n">memory_size</span><span class="p">;</span>     <span class="c1">// 内存大小，单位 bytes
</span></span></span><span class="line"><span class="cl">    <span class="n">__u64</span> <span class="n">userspace_addr</span><span class="p">;</span>  <span class="c1">// 从 QEMU 进程地址空间中分配内存的起始地址，即 HVA
</span></span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p><code>KVM_SET_USER_MEMORY_REGION</code>这个 <code>ioctl</code> 主要目的就是设置<code>GPA-&gt;HVA</code>的映射关系，KVM 会继续调用<code>kvm_vm_ioctl_set_memory_region()</code>，在内核空间维护并管理 Guest 的内存。</p>
<h2 id="相关数据结构">相关数据结构</h2>
<h3 id="addressspace">AddressSpace</h3>
<h4 id="结构体定义">结构体定义</h4>
<p>QEMU 用 AddressSpace 结构体表示 Guest 中 CPU/设备看到的内存【也就是Guest OS 可以在 QEMU 进程虚存中用到的所有内存，是 MemoryRegion 的集合，即 GPA 的整体】，类似于物理机中地址空间的概念，但在这里表示的是 Guest 的一段地址空间，如内存地址空间 <code>address_space_memory</code> 、<code>I/O</code> 地址空间<code>address_space_io</code>，它在 QEMU 源码<code>memory.c</code>中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * struct AddressSpace: describes a mapping of addresses to #MemoryRegion objects
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">AddressSpace</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* private: */</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">rcu_head</span> <span class="n">rcu</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">root</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Accessed via RCU.  */</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">FlatView</span> <span class="o">*</span><span class="n">current_map</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">ioeventfd_nb</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">MemoryRegionIoeventfd</span> <span class="o">*</span><span class="n">ioeventfds</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_HEAD</span><span class="p">(,</span> <span class="n">MemoryListener</span><span class="p">)</span> <span class="n">listeners</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_ENTRY</span><span class="p">(</span><span class="n">AddressSpace</span><span class="p">)</span> <span class="n">address_spaces_link</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>每个 AddressSpace 一般包含一系列的 MemoryRegion：<code>root</code>指针指向根级 MemoryRegion，而 root 可能有自己的若干个 sub-regions（子节点），于是形成树状结构。这些 MemoryRegion 通过树连接起来，树的根即为 AddressSpace 的 root 域。</p>
<h4 id="全局变量">全局变量</h4>
<p>另外，QEMU 中有两个全局的静态 AddressSpace，在 memory.c 中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="n">AddressSpace</span> <span class="n">address_space_memory</span><span class="p">;</span> <span class="c1">// 内存地址空间
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">AddressSpace</span> <span class="n">address_space_io</span><span class="p">;</span>     <span class="c1">// I/O 地址空间
</span></span></span></code></pre></div><p>其 root 域分别指向之后会提到的两个 MemoryRegion 类型变量：system_memory、system_io。</p>
<h3 id="memoryregion">MemoryRegion</h3>
<h4 id="结构体定义-1">结构体定义</h4>
<p><code>MemoryRegion</code> 表示在 <code>Guest Memory Layout</code> 中的一段内存区域【也就是单元级 GPA 的概念，Guest OS 可以管理到的那些 Guest 物理内存单元】，它是联系 <code>GPA</code> 和 <code>RAMBlocks</code>（描述真实内存）之间的桥梁，在<code>memory.h</code>中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">MemoryRegion</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* All fields are private - violators will be prosecuted */</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="n">MemoryRegionOps</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span>      <span class="c1">// 回调函数集合
</span></span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">parent</span><span class="p">;</span>            <span class="c1">// 父 MemoryRegion 指针
</span></span></span><span class="line"><span class="cl">    <span class="n">Int128</span> <span class="n">size</span><span class="p">;</span>                     <span class="c1">// 该区域内存的大小
</span></span></span><span class="line"><span class="cl">    <span class="kt">target_phys_addr_t</span> <span class="n">addr</span><span class="p">;</span>         <span class="c1">// 在 Address Space 中的地址，即 HVA
</span></span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">destructor</span><span class="p">)(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">ram_addr_t</span> <span class="n">ram_addr</span><span class="p">;</span>             <span class="c1">// MemoryRegion 的起始地址，即 GPA
</span></span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">subpage</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">terminates</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">readable</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">ram</span><span class="p">;</span>                        <span class="c1">// 是否表示 RAM
</span></span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">readonly</span><span class="p">;</span> <span class="cm">/* For RAM regions */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">enabled</span><span class="p">;</span>                    <span class="c1">// 是否已经通知 KVM 使用这段内存
</span></span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">rom_device</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">warning_printed</span><span class="p">;</span> <span class="cm">/* For reservations */</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">alias</span><span class="p">;</span>             <span class="c1">// 是否为 MemoryRegion alias
</span></span></span><span class="line"><span class="cl">    <span class="kt">target_phys_addr_t</span> <span class="n">alias_offset</span><span class="p">;</span> <span class="c1">// 若为 alias，在原 MemoryRegion 中的 offset
</span></span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="n">priority</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">may_overlap</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_HEAD</span><span class="p">(</span><span class="n">subregions</span><span class="p">,</span> <span class="n">MemoryRegion</span><span class="p">)</span> <span class="n">subregions</span><span class="p">;</span> <span class="c1">// 子区域链表头
</span></span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_ENTRY</span><span class="p">(</span><span class="n">MemoryRegion</span><span class="p">)</span> <span class="n">subregions_link</span><span class="p">;</span>       <span class="c1">// 子区域链表节点
</span></span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_HEAD</span><span class="p">(</span><span class="n">coalesced_ranges</span><span class="p">,</span> <span class="n">CoalescedMemoryRange</span><span class="p">)</span> <span class="n">coalesced</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span>       <span class="c1">// MemoryRegion 的名字，调试时使用
</span></span></span><span class="line"><span class="cl">    <span class="kt">uint8_t</span> <span class="n">dirty_log_mask</span><span class="p">;</span> <span class="c1">// 表示哪一种 dirty map 被使用，共分三种
</span></span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="n">ioeventfd_nb</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegionIoeventfd</span> <span class="o">*</span><span class="n">ioeventfds</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h4 id="全局变量-1">全局变量</h4>
<p>在 QEMU 的 exec.c 中也定义了两个静态的 MemoryRegion 指针变量：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">system_memory</span><span class="p">;</span> <span class="c1">// 内存 MemoryRegion，对应 address_space_memory
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">system_io</span><span class="p">;</span>     <span class="c1">// I/O MemoryRegion，对应 address_space_io
</span></span></span></code></pre></div><p>与两个全局 AddressSpace 对应，即 AddressSpace 的 root 域指向这两个 MemoryRegion。</p>
<h4 id="memoryregion-的类型">MemoryRegion 的类型</h4>
<p>MemoryRegion 有多种类型，可以表示一段 RAM、ROM、MMIO、alias(别名)。</p>
<p>若为 alias 则表示一个 MemoryRegion 的部分区域，例如，QEMU 会为 pc.ram 这个表示 RAM 的 MemoryRegion 添加两个 alias：ram-below-4g 和 ram-above-4g，之后会看到具体的代码实例。</p>
<p>另外，MemoryRegion 也可以表示一个 container，这就表示它只是其他若干个 MemoryRegion 的容器。</p>
<p>那么要如何创建不同类型的 <code>MemoryRegion</code> 呢？</p>
<p>在 QEMU 中实际上是通过调用不同的初始化函数区分的。根据不同的初始化函数及其功能，可以将 MemoryRegion 划分为以下三种类型：</p>
<ul>
<li>根级 MemoryRegion：直接通过 memory_region_init 初始化，没有自己的内存，用于管理 subregion，例如 system_memory：</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">memory_region_init</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="kt">uint64_t</span> <span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">ops</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">parent</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">size</span> <span class="o">=</span> <span class="nf">int128_make64</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">size</span> <span class="o">==</span> <span class="n">UINT64_MAX</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">mr</span><span class="o">-&gt;</span><span class="n">size</span> <span class="o">=</span> <span class="nf">int128_2_64</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">addr</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">subpage</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">enabled</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">terminates</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">// 非实体 MemoryRegion，搜索时会继续前往其 subregions
</span></span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">ram</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>        <span class="c1">// 根级 MemoryRegion 不分配内存
</span></span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">readable</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">readonly</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">rom_device</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">destructor</span> <span class="o">=</span> <span class="n">memory_region_destructor_none</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">priority</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">may_overlap</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">alias</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_INIT</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mr</span><span class="o">-&gt;</span><span class="n">subregions</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">memset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mr</span><span class="o">-&gt;</span><span class="n">subregions_link</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="n">mr</span><span class="o">-&gt;</span><span class="n">subregions_link</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_INIT</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mr</span><span class="o">-&gt;</span><span class="n">coalesced</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">name</span> <span class="o">=</span> <span class="nf">g_strdup</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">dirty_log_mask</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">ioeventfd_nb</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">ioeventfds</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>可以看到 mr-&gt;addr 被设置为 0，而 mr-&gt;ram_addr 则并没有初始化。</p>
<ul>
<li>实体 <code>MemoryRegion</code>：通过<code>memory_region_init_ram()</code>初始化，有自己的内存（从 QEMU 进程地址空间中分配），大小为<code>size</code>，例如<code>ram_memory</code>、 <code>pci_memory</code>：</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="nf">pc_memory_init</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">system_memory</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kernel_filename</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kernel_cmdline</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">initrd_filename</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="kt">ram_addr_t</span> <span class="n">below_4g_mem_size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="kt">ram_addr_t</span> <span class="n">above_4g_mem_size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">rom_memory</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">MemoryRegion</span> <span class="o">**</span><span class="n">ram_memory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">ram</span><span class="p">,</span> <span class="o">*</span><span class="n">option_rom_mr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* ...*/</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Allocate RAM.  We allocate it as a single memory region and use
</span></span></span><span class="line"><span class="cl"><span class="cm">     * aliases to address portions of it, mostly for backwards compatibility
</span></span></span><span class="line"><span class="cl"><span class="cm">     * with older qemus that used qemu_ram_alloc().
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">    <span class="n">ram</span> <span class="o">=</span> <span class="nf">g_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">ram</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 调用 memory_region_init_ram 对 ram_memory 进行初始化
</span></span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init_ram</span><span class="p">(</span><span class="n">ram</span><span class="p">,</span> <span class="s">&#34;pc.ram&#34;</span><span class="p">,</span> <span class="n">below_4g_mem_size</span> <span class="o">+</span> <span class="n">above_4g_mem_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">vmstate_register_ram_global</span><span class="p">(</span><span class="n">ram</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="n">ram_memory</span> <span class="o">=</span> <span class="n">ram</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* ... */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">memory_region_init_ram</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                            <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                            <span class="kt">uint64_t</span> <span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init</span><span class="p">(</span><span class="n">mr</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">ram</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">terminates</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">destructor</span> <span class="o">=</span> <span class="n">memory_region_destructor_ram</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">ram_addr</span> <span class="o">=</span> <span class="nf">qemu_ram_alloc</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">mr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>可以看到这里是先调用了<code>memory_region_init()</code>，之后设置 <code>RAM</code> 属性，并继续调用<code>qemu_ram_alloc()</code>分配内存。</p>
<ul>
<li>别名 <code>MemoryRegion</code>：通过<code>memory_region_init_alias()</code> 初始化，没有自己的内存，表示实体 <code>MemoryRegion</code> 的一部分。通过 <code>alias</code> 成员指向实体 <code>MemoryRegion</code>，<code>alias_offset</code>为在实体 <code>MemoryRegion</code> 中的偏移量，例如<code>ram_below_4g</code>、<code>ram_above_4g</code>：</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="nf">pc_memory_init</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">system_memory</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kernel_filename</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kernel_cmdline</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">initrd_filename</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="kt">ram_addr_t</span> <span class="n">below_4g_mem_size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="kt">ram_addr_t</span> <span class="n">above_4g_mem_size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">rom_memory</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">MemoryRegion</span> <span class="o">**</span><span class="n">ram_memory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">ram_below_4g</span><span class="p">,</span> <span class="o">*</span><span class="n">ram_above_4g</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* ... */</span>
</span></span><span class="line"><span class="cl">    <span class="n">ram_below_4g</span> <span class="o">=</span> <span class="nf">g_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">ram_below_4g</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 调用 memory_region_init_alias 对 ram_below_4g 进行初始化
</span></span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init_alias</span><span class="p">(</span><span class="n">ram_below_4g</span><span class="p">,</span> <span class="s">&#34;ram-below-4g&#34;</span><span class="p">,</span> <span class="n">ram</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">below_4g_mem_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* ..
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">memory_region_init_alias</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                              <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                              <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">orig</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                              <span class="kt">target_phys_addr_t</span> <span class="n">offset</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                              <span class="kt">uint64_t</span> <span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init</span><span class="p">(</span><span class="n">mr</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">alias</span> <span class="o">=</span> <span class="n">orig</span><span class="p">;</span> <span class="c1">// 指向实体 MemoryRegion
</span></span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">alias_offset</span> <span class="o">=</span> <span class="n">offset</span><span class="p">;</span> <span class="c1">//通过 offset 得到实体的某一个部分
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="ramblock">RAMBlock</h3>
<h4 id="结构体定义-2">结构体定义</h4>
<p><code>MemoryRegion</code> 用来描述一段逻辑层面上的内存区域，而记录实际分配的内存地址信息的结构体则是 <code>RAMBlock</code>，在<code>ramblock.h</code>中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">RAMBlock</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">rcu_head</span> <span class="n">rcu</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">host</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint8_t</span> <span class="o">*</span><span class="n">colo_cache</span><span class="p">;</span> <span class="cm">/* For colo, VM&#39;s ram cache */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">ram_addr_t</span> <span class="n">offset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">ram_addr_t</span> <span class="n">used_length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">ram_addr_t</span> <span class="n">max_length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">resized</span><span class="p">)(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">length</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">host</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">flags</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Protected by iothread lock.  */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="n">idstr</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* RCU-enabled, writes protected by the ramlist lock */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QLIST_ENTRY</span><span class="p">(</span><span class="n">RAMBlock</span><span class="p">)</span> <span class="n">next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QLIST_HEAD</span><span class="p">(,</span> <span class="n">RAMBlockNotifier</span><span class="p">)</span> <span class="n">ramblock_notifiers</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">size_t</span> <span class="n">page_size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* dirty bitmap used during migration */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">bmap</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* bitmap of already received pages in postcopy */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">receivedmap</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">     * bitmap to track already cleared dirty bitmap.  When the bit is
</span></span></span><span class="line"><span class="cl"><span class="cm">     * set, it means the corresponding memory chunk needs a log-clear.
</span></span></span><span class="line"><span class="cl"><span class="cm">     * Set this up to non-NULL to enable the capability to postpone
</span></span></span><span class="line"><span class="cl"><span class="cm">     * and split clearing of dirty bitmap on the remote node (e.g.,
</span></span></span><span class="line"><span class="cl"><span class="cm">     * KVM).  The bitmap will be set only when doing global sync.
</span></span></span><span class="line"><span class="cl"><span class="cm">     *
</span></span></span><span class="line"><span class="cl"><span class="cm">     * NOTE: this bitmap is different comparing to the other bitmaps
</span></span></span><span class="line"><span class="cl"><span class="cm">     * in that one bit can represent multiple guest pages (which is
</span></span></span><span class="line"><span class="cl"><span class="cm">     * decided by the `clear_bmap_shift&#39; variable below).  On
</span></span></span><span class="line"><span class="cl"><span class="cm">     * destination side, this should always be NULL, and the variable
</span></span></span><span class="line"><span class="cl"><span class="cm">     * `clear_bmap_shift&#39; is meaningless.
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">clear_bmap</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint8_t</span> <span class="n">clear_bmap_shift</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">     * RAM block length that corresponds to the used_length on the migration
</span></span></span><span class="line"><span class="cl"><span class="cm">     * source (after RAM block sizes were synchronized). Especially, after
</span></span></span><span class="line"><span class="cl"><span class="cm">     * starting to run the guest, used_length and postcopy_length can differ.
</span></span></span><span class="line"><span class="cl"><span class="cm">     * Used to register/unregister uffd handlers and as the size of the received
</span></span></span><span class="line"><span class="cl"><span class="cm">     * bitmap. Receiving any page beyond this length will bail out, as it
</span></span></span><span class="line"><span class="cl"><span class="cm">     * could not have been valid on the source.
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">ram_addr_t</span> <span class="n">postcopy_length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>可以看到在 <code>RAMBlock</code> 中 host 和 offset 域分别对应了 <code>HVA</code> 和<code>GPA</code>，因此也可以说 <code>RAMBlock</code> 中存储了<code>GPA-&gt;HVA</code>的映射关系，另外每一个 <code>RAMBlock</code> 都会指向其所属的 <code>MemoryRegion</code>。</p>
<h4 id="全局变量-ram_list">全局变量 ram_list</h4>
<p>QEMU 在<code>ramlist.h</code>中定义了一个全局变量<code>ram_list</code>，以链表的形式维护了所有的 <code>RAMBlock</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="n">RAMList</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">QemuMutex</span> <span class="n">mutex</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">RAMBlock</span> <span class="o">*</span><span class="n">mru_block</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* RCU-enabled, writes protected by the ramlist lock. */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QLIST_HEAD</span><span class="p">(,</span> <span class="n">RAMBlock</span><span class="p">)</span> <span class="n">blocks</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">DirtyMemoryBlocks</span> <span class="o">*</span><span class="n">dirty_memory</span><span class="p">[</span><span class="n">DIRTY_MEMORY_NUM</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span> <span class="n">version</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QLIST_HEAD</span><span class="p">(,</span> <span class="n">RAMBlockNotifier</span><span class="p">)</span> <span class="n">ramblock_notifiers</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">RAMList</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="n">RAMList</span> <span class="n">ram_list</span><span class="p">;</span>
</span></span></code></pre></div><p>每一个新分配的 <code>RAMBlock</code> 都会被插入到<code>ram_list</code>的头部。如需查找地址所对应的 <code>RAMBlock</code>，则需要遍历<code>ram_list</code>，当目标地址落在当前<code>RAMBlock</code>的地址区间时，该 <code>RAMBlock</code> 即为查找目标。</p>
<h4 id="asmrramblock-之间的关系">AS、MR、RAMBlock 之间的关系</h4>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220225155936.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220225155936.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="flatview">FlatView</h3>
<p>AddressSpace 的 root 域及其子树共同构成了 Guest 的物理地址空间，但这些都是在 QEMU 侧定义的。要传入 KVM 进行设置时，复杂的树状结构是不利于内核进行处理的，因此需要将其<strong>转换为一个“平坦”的地址模</strong>型，也就是一个从零开始、只包含地址信息的数据结构，这在 QEMU 中通过 <strong>FlatView</strong> 来表示。每个 AddressSpace 都有一个与之对应的 FlatView 指针 current_map，表示其对应的平面展开视图。</p>
<h4 id="结构体定义-3">结构体定义</h4>
<p><code>FlatView</code> 在<code>memory.c</code>中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/* Flattened global view of current active memory hierarchy.  Kept in sorted
</span></span></span><span class="line"><span class="cl"><span class="cm"> * order.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">FlatView</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">rcu_head</span> <span class="n">rcu</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="n">ref</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">FlatRange</span> <span class="o">*</span><span class="n">ranges</span><span class="p">;</span>      <span class="c1">// 对应的 FlatRange 数组
</span></span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="n">nr</span><span class="p">;</span>            <span class="c1">// FlatRange 的数目
</span></span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="n">nr_allocated</span><span class="p">;</span>  <span class="c1">// 当前数组的项数
</span></span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">AddressSpaceDispatch</span> <span class="o">*</span><span class="n">dispatch</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">root</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>其中，<code>ranges</code>是一个数组，记录了 <code>FlatView</code> 下所有的 <code>FlatRange</code>。</p>
<h4 id="flatrange">FlatRange</h4>
<p>在 <code>FlatView</code> 中，<code>FlatRange</code> 表示在 <code>FlatView</code> 中的一段内存范围，同样在<code>memory.c</code>中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* Range of memory in the global map.  Addresses are absolute. */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">FlatRange</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">;</span>           <span class="c1">// 指向所属的 MemoryRegion
</span></span></span><span class="line"><span class="cl">    <span class="n">hwaddr</span> <span class="n">offset_in_region</span><span class="p">;</span>    <span class="c1">// 在全局 MemoryRegion 中的 offset，对应 GPA
</span></span></span><span class="line"><span class="cl">    <span class="n">AddrRange</span> <span class="n">addr</span><span class="p">;</span>             <span class="c1">// 代表的地址区间，对应 HVA
</span></span></span><span class="line"><span class="cl">    <span class="kt">uint8_t</span> <span class="n">dirty_log_mask</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">romd_mode</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">readonly</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">nonvolatile</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>每个 <code>FlatRange</code> 对应一段虚拟机物理地址区间，各个 <code>FlatRange</code> 不会重叠，<strong>按照地址的顺序保存在数组中</strong>，具体的地址范围由一个 <code>AddrRange</code> 结构来描述：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm"> * AddrRange 用于表示 FlatRange 的起始地址及大小
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">AddrRange</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">Int128</span> <span class="n">start</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">Int128</span> <span class="n">size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h3 id="memoryregionsection">MemoryRegionSection</h3>
<h4 id="结构体定义-4">结构体定义</h4>
<p>在 <code>QEMU</code> 中，还有几个起到中介作用的结构体，<code>MemoryRegionSection</code> 就是其中之一。</p>
<p>之前介绍的 <code>FlatRange</code> 代表一个物理地址空间的片段，偏向于描述在 <code>Host</code> 侧即 <strong>AddressSpace 中的分布【Guest 的物理空间】</strong>，而 <code>MemoryRegionSection</code> 则代表在 <code>Guest</code> 侧即 <strong>MemoryRegion 中的片段</strong>。<code>MemoryRegionSection</code> 在<code>memory.h</code>中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * MemoryRegionSection: describes a fragment of a #MemoryRegion
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @mr: the region, or %NULL if empty
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @address_space: the address space the region is mapped in
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @offset_within_region: the beginning of the section, relative to @mr&#39;s start
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @size: the size of the section; will not exceed @mr&#39;s boundaries
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @offset_within_address_space: the address of the first byte of the section
</span></span></span><span class="line"><span class="cl"><span class="cm"> *     relative to the region&#39;s address space
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @readonly: writes to this section are ignored
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"> <span class="c1">//只是起到描述的作用，描述了是哪个 AddressSpace 的 MemoryRegion，
</span></span></span><span class="line"><span class="cl"> <span class="c1">//并且在 MemoryRegion 中的 offset，和在 AddressSpace 展开为平坦内存的 offset
</span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">MemoryRegionSection</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">;</span>                               <span class="c1">// 所属的 MemoryRegion
</span></span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">address_space</span><span class="p">;</span>                    <span class="c1">// 关联的 AddressSpace
</span></span></span><span class="line"><span class="cl">    <span class="kt">target_phys_addr_t</span> <span class="n">offset_within_region</span><span class="p">;</span>        <span class="c1">// 在 MemoryRegion 内部的 offset
</span></span></span><span class="line"><span class="cl">    <span class="kt">uint64_t</span> <span class="n">size</span><span class="p">;</span>                                  <span class="c1">// Section 的大小
</span></span></span><span class="line"><span class="cl">    <span class="kt">target_phys_addr_t</span> <span class="n">offset_within_address_space</span><span class="p">;</span> <span class="c1">// 在 AddressSpace 内部的 offset
</span></span></span><span class="line"><span class="cl">    <span class="kt">bool</span> <span class="n">readonly</span><span class="p">;</span>                                  <span class="c1">// 是否为只读
</span></span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><ul>
<li><code>offset_within_region</code>：在所属 <code>MemoryRegion</code> 中的<code>offset</code>。一个<code>AddressSpace</code> 可能由多个 <code>MemoryRegion</code> 组成，因此该 <code>offset</code> 是局部的</li>
<li><code>offset_within_address_space</code>：在所属 <code>AddressSpace</code> 中的 <code>offset</code>，它是全局的</li>
</ul>
<h4 id="和其他数据结构之间的关系">和其他数据结构之间的关系</h4>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125110422.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125110422.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<ul>
<li><code>AddressSpace</code> 的<code>root</code>指向对应的根级<code>MemoryRegion</code>，<code>current_map</code>指向<code>AddressSpace</code> 的<code>root</code>通过<code>generate_memory_topology()</code>生成的 <code>FlatView</code></li>
<li><code>FlatView</code> 中的<code>ranges</code>数组表示该<code>MemoryRegion</code> 所表示的<code>Guest</code>地址区间【GPA 的整个平坦物理空间】，并按照地址的顺序进行排列</li>
<li><code>MemoryRegionSection</code> 由<code>ranges</code>数组中的 <code>FlatRange</code> 对应生成，作为注册到 <code>KVM</code>中的基本单位</li>
</ul>
<hr>
<p><code>QEMU</code> 在用户空间申请内存后，需要将内存信息通过一系列系统调用传入内核空间的 <code>KVM</code>，由 <code>KVM</code> 侧进行管理，因此 <code>QEMU</code> 侧也定义了一些用于向 <code>KVM</code> 传递参数的结构体。</p>
<p>以下为<code>KVM</code>相关的数据结构。</p>
<h3 id="kvmslot">KVMSlot</h3>
<p><code>在 kvm_init.h</code>中定义，是 <code>KVM</code> 中内存管理的基本单位：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">typedef</span> <span class="k">struct</span> <span class="n">KVMSlot</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">hwaddr</span> <span class="n">start_addr</span><span class="p">;</span> <span class="c1">// Guest 物理地址，GPA
</span></span></span><span class="line"><span class="cl">    <span class="kt">ram_addr_t</span> <span class="n">memory_size</span><span class="p">;</span>        <span class="c1">// 内存大小
</span></span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="o">*</span><span class="n">ram</span><span class="p">;</span> <span class="c1">// QEMU 用户空间地址，HVA
</span></span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">slot</span><span class="p">;</span>  <span class="c1">// Slot 编号
</span></span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">flags</span><span class="p">;</span> <span class="c1">// 标志位，例如是否追踪脏页、是否可用等
</span></span></span><span class="line"><span class="cl">    <span class="cm">/* Dirty bitmap cache for the slot */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">dirty_bmap</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">dirty_bmap_size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Cache of the address space ID */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">as_id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Cache of the offset in ram address space */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">ram_addr_t</span> <span class="n">ram_start_offset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">KVMSlot</span><span class="p">;</span>
</span></span></code></pre></div><p><code>KVMSlot</code> 类似于内存插槽的概念。</p>
<h3 id="kvm_userspace_memory_region">kvm_userspace_memory_region</h3>
<p>调用<code>ioctl(KVM_SET_USER_MEMORY_REGION)</code>时需要向 <code>KVM</code> 传递的参数，在<code>kvm.h</code>中定义</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* for KVM_SET_USER_MEMORY_REGION */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">kvm_userspace_memory_region</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">__u32</span> <span class="n">slot</span><span class="p">;</span>            <span class="c1">// slot 编号
</span></span></span><span class="line"><span class="cl">    <span class="n">__u32</span> <span class="n">flags</span><span class="p">;</span>           <span class="c1">// 标志位，例如是否追踪脏页、是否可用等
</span></span></span><span class="line"><span class="cl">    <span class="n">__u64</span> <span class="n">guest_phys_addr</span><span class="p">;</span> <span class="c1">// Guest 物理地址，GPA
</span></span></span><span class="line"><span class="cl">    <span class="n">__u64</span> <span class="n">memory_size</span><span class="p">;</span>     <span class="c1">// 内存大小，bytes
</span></span></span><span class="line"><span class="cl">    <span class="n">__u64</span> <span class="n">userspace_addr</span><span class="p">;</span>  <span class="c1">// 从 QEMU 进程空间分配的起始地址，HVA
</span></span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h3 id="memorylistener">MemoryListener</h3>
<h4 id="结构体定义-5">结构体定义</h4>
<p>为了监控虚拟机的物理地址访问，对于每一个 <code>AddressSpace</code>，都会有一个 <code>MemoryListener</code> 与之对应。每当物理映射<code>GPA-&gt;HVA</code>发生改变时，就会回调这些函数。<strong>MemoryListener</strong> 是对一些事件的<strong>回调函数合集</strong>，在<code>memory.h</code>中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * MemoryListener: callbacks structure for updates to the physical memory map
</span></span></span><span class="line"><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Allows a component to adjust to changes in the guest-visible memory map.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Use with memory_listener_register() and memory_listener_unregister().
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">MemoryListener</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">begin</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">commit</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">region_add</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">MemoryRegionSection</span> <span class="o">*</span><span class="n">section</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">region_del</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">MemoryRegionSection</span> <span class="o">*</span><span class="n">section</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">region_nop</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">MemoryRegionSection</span> <span class="o">*</span><span class="n">section</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">log_start</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">MemoryRegionSection</span> <span class="o">*</span><span class="n">section</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">log_stop</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">MemoryRegionSection</span> <span class="o">*</span><span class="n">section</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">log_sync</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">MemoryRegionSection</span> <span class="o">*</span><span class="n">section</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">log_global_start</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">log_global_stop</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">eventfd_add</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">MemoryRegionSection</span> <span class="o">*</span><span class="n">section</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="kt">bool</span> <span class="n">match_data</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">data</span><span class="p">,</span> <span class="n">EventNotifier</span> <span class="o">*</span><span class="n">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">eventfd_del</span><span class="p">)(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">MemoryRegionSection</span> <span class="o">*</span><span class="n">section</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="kt">bool</span> <span class="n">match_data</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">data</span><span class="p">,</span> <span class="n">EventNotifier</span> <span class="o">*</span><span class="n">e</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Lower = earlier (during add), later (during del) */</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="n">priority</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">address_space_filter</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_ENTRY</span><span class="p">(</span><span class="n">MemoryListener</span><span class="p">)</span> <span class="n">link</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h4 id="全局变量-memory_listeners">全局变量 memory_listeners</h4>
<p>所有的 <code>MemoryListener</code> 都会挂在全局变量<code>memory_listeners</code>链表上，在<code>memory.c</code>中定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="nf">QTAILQ_HEAD</span><span class="p">(,</span> <span class="n">MemoryListener</span><span class="p">)</span> <span class="n">memory_listeners</span>
</span></span><span class="line"><span class="cl">    <span class="o">=</span> <span class="nf">QTAILQ_HEAD_INITIALIZER</span><span class="p">(</span><span class="n">memory_listeners</span><span class="p">);</span>
</span></span></code></pre></div><p>在<code>memory.c</code>中枚举了<code>ListenerDirection</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">enum</span> <span class="n">ListenerDirection</span> <span class="p">{</span> <span class="n">Forward</span><span class="p">,</span> <span class="n">Reverse</span> <span class="p">};</span>
</span></span></code></pre></div><h3 id="重要数据结构总览">重要数据结构总览</h3>
<table>
	<thead>
			<tr>
					<th style="text-align: center">结构体名</th>
					<th style="text-align: left">说明</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: center">AddressSpace</td>
					<td style="text-align: left">VM 能看到的一段地址空间，偏向 Host 侧【注意指的是偏向】</td>
			</tr>
			<tr>
					<td style="text-align: center">MemoryRegion</td>
					<td style="text-align: left">地址空间中一段逻辑层面的内存区域，偏向 Guest 侧</td>
			</tr>
			<tr>
					<td style="text-align: center">RAMBlock</td>
					<td style="text-align: left">记录实际分配的内存地址信息，存储了 GPA-&gt;HVA 的映射关系</td>
			</tr>
			<tr>
					<td style="text-align: center">FlatView</td>
					<td style="text-align: left">MemoryRegion 对应的平面展开视图，包含一个 FlatRange 类型的 ranges 数组</td>
			</tr>
			<tr>
					<td style="text-align: center">FlatRange</td>
					<td style="text-align: left">对应一段虚拟机物理地址区间，各个 FlatRange 不会重叠，按照地址的顺序保存在数组中</td>
			</tr>
			<tr>
					<td style="text-align: center">MemoryRegionSection</td>
					<td style="text-align: left">表示 MemoryRegion 中的片段</td>
			</tr>
			<tr>
					<td style="text-align: center">MemoryListener</td>
					<td style="text-align: left">回调函数集合</td>
			</tr>
			<tr>
					<td style="text-align: center">KVMSlot</td>
					<td style="text-align: left">KVM 中内存管理的基本单位，表示一个内存插槽</td>
			</tr>
			<tr>
					<td style="text-align: center">kvm_userspace_memory_region</td>
					<td style="text-align: left">调用 ioctl(KVM_SET_USER_MEMORY_REGION) 时需要向 KVM 传递的参数</td>
			</tr>
	</tbody>
</table>
<h2 id="具体实现机制">具体实现机制</h2>
<p>QEMU 的内存申请流程大致可分为三个部分：回调函数的注册、AddressSpace 的初始化、实际内存的分配。下面将根据在 vl.c 的 main() 函数中的调用顺序分别介绍。</p>
<h3 id="回调函数的注册">回调函数的注册</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125133808.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125133808.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="err">└─</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">configure_accelerator</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">       <span class="err">└─</span> <span class="kt">int</span> <span class="nf">kvm_init</span><span class="p">()</span>                                     <span class="c1">// 初始化 KVM
</span></span></span><span class="line"><span class="cl">            <span class="err">├─</span> <span class="kt">int</span> <span class="nf">kvm_ioctl</span><span class="p">(</span><span class="n">KVM_CREATE_VM</span><span class="p">)</span>                  <span class="c1">// 创建 VM
</span></span></span><span class="line"><span class="cl">            <span class="err">├─</span> <span class="kt">int</span> <span class="nf">kvm_arch_init</span><span class="p">()</span>                           <span class="c1">// 针对不同的架构进行初始化
</span></span></span><span class="line"><span class="cl">            <span class="err">└─</span> <span class="kt">void</span> <span class="nf">memory_listener_register</span><span class="p">()</span>               <span class="c1">// 注册 kvm_memory_listener
</span></span></span><span class="line"><span class="cl">                 <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">listener_add_address_space</span><span class="p">()</span> <span class="c1">// 调用 region_add 回调
</span></span></span><span class="line"><span class="cl">                      <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">kvm_region_add</span><span class="p">()</span>        <span class="c1">// region_add 对应的回调实现
</span></span></span><span class="line"><span class="cl">                           <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">kvm_set_phys_mem</span><span class="p">()</span> <span class="c1">// 根据传入的 section 填充 KVMSlot
</span></span></span><span class="line"><span class="cl">                                <span class="err">└─</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">kvm_set_user_memory_region</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                                     <span class="err">└─</span> <span class="kt">int</span> <span class="nf">ioctl</span><span class="p">(</span><span class="n">KVM_SET_USER_MEMORY_REGION</span><span class="p">)</span>
</span></span></code></pre></div><p>进入<code>configure_accelerator()</code>后，<code>QEMU</code>会先调用<code>configure_accelerator()</code>设置 <code>KVM</code> 的加速支持，之后进入<code>kvm_init()</code>。该函数主要完成对 KVM 的初始化，包括一些常规检查如 <code>CPU</code> 个数、<code>KVM</code> 版本等，之后通过<code>kvm_ioctl(KVM_CREATE_VM)</code>与内核交互，创建 <code>KVM</code> 虚拟机。在<code>kvm_init()</code>的最后，会调用<code>memory_listener_register()</code>注册<code>kvm_memory_listener</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">kvm_init</span><span class="p">(</span><span class="n">MachineState</span> <span class="o">*</span><span class="n">ms</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MachineClass</span> <span class="o">*</span><span class="n">mc</span> <span class="o">=</span> <span class="nf">MACHINE_GET_CLASS</span><span class="p">(</span><span class="n">ms</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 打开/dev/kvm
</span></span></span><span class="line"><span class="cl">    <span class="n">s</span><span class="o">-&gt;</span><span class="n">fd</span> <span class="o">=</span> <span class="nf">qemu_open_old</span><span class="p">(</span><span class="s">&#34;/dev/kvm&#34;</span><span class="p">,</span> <span class="n">O_RDWR</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 创建 VM
</span></span></span><span class="line"><span class="cl">    <span class="k">do</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ret</span> <span class="o">=</span> <span class="nf">kvm_ioctl</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">KVM_CREATE_VM</span><span class="p">,</span> <span class="n">type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">ret</span> <span class="o">==</span> <span class="o">-</span><span class="n">EINTR</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* ... */</span>
</span></span><span class="line"><span class="cl">    <span class="n">ret</span> <span class="o">=</span> <span class="nf">kvm_arch_init</span><span class="p">(</span><span class="n">s</span><span class="p">);</span> <span class="c1">// 针对不同的架构进行初始化
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 对于以下 AddressSpace，设置其对应的 listener
</span></span></span><span class="line"><span class="cl">    <span class="nf">kvm_memory_listener_register</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">s</span><span class="o">-&gt;</span><span class="n">memory_listener</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                                 <span class="o">&amp;</span><span class="n">address_space_memory</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">&#34;kvm-memory&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">memory_listener_register</span><span class="p">(</span><span class="o">&amp;</span><span class="n">kvm_coalesced_pio_listener</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                             <span class="o">&amp;</span><span class="n">address_space_io</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* ... */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">memory_listener_register</span><span class="p">(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span> <span class="n">AddressSpace</span> <span class="o">*</span><span class="n">as</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryListener</span> <span class="o">*</span><span class="n">other</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Only one of them can be defined for a listener */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">assert</span><span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">listener</span><span class="o">-&gt;</span><span class="n">log_sync</span> <span class="o">&amp;&amp;</span> <span class="n">listener</span><span class="o">-&gt;</span><span class="n">log_sync_global</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">listener</span><span class="o">-&gt;</span><span class="n">address_space</span> <span class="o">=</span> <span class="n">as</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">QTAILQ_EMPTY</span><span class="p">(</span><span class="o">&amp;</span><span class="n">memory_listeners</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">||</span> <span class="n">listener</span><span class="o">-&gt;</span><span class="n">priority</span> <span class="o">&gt;=</span> <span class="nf">QTAILQ_LAST</span><span class="p">(</span><span class="o">&amp;</span><span class="n">memory_listeners</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">priority</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">QTAILQ_INSERT_TAIL</span><span class="p">(</span><span class="o">&amp;</span><span class="n">memory_listeners</span><span class="p">,</span> <span class="n">listener</span><span class="p">,</span> <span class="n">link</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">QTAILQ_FOREACH</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">memory_listeners</span><span class="p">,</span> <span class="n">link</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="o">-&gt;</span><span class="n">priority</span> <span class="o">&lt;</span> <span class="n">other</span><span class="o">-&gt;</span><span class="n">priority</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nf">QTAILQ_INSERT_BEFORE</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">listener</span><span class="p">,</span> <span class="n">link</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">QTAILQ_EMPTY</span><span class="p">(</span><span class="o">&amp;</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">listeners</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="o">||</span> <span class="n">listener</span><span class="o">-&gt;</span><span class="n">priority</span> <span class="o">&gt;=</span> <span class="nf">QTAILQ_LAST</span><span class="p">(</span><span class="o">&amp;</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">listeners</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">priority</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">QTAILQ_INSERT_TAIL</span><span class="p">(</span><span class="o">&amp;</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">listeners</span><span class="p">,</span> <span class="n">listener</span><span class="p">,</span> <span class="n">link_as</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">QTAILQ_FOREACH</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">listeners</span><span class="p">,</span> <span class="n">link_as</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="o">-&gt;</span><span class="n">priority</span> <span class="o">&lt;</span> <span class="n">other</span><span class="o">-&gt;</span><span class="n">priority</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nf">QTAILQ_INSERT_BEFORE</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">listener</span><span class="p">,</span> <span class="n">link_as</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">listener_add_address_space</span><span class="p">(</span><span class="n">listener</span><span class="p">,</span> <span class="n">as</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>最后的<code>listener_add_address_space()</code>主要是将 listener 注册到其对应的 <code>AddressSpace</code> 上，并根据 <code>AddressSpace</code> 对应的 <code>FlatRange</code> 数组，生成 <code>MemoryRegionSection</code>【<code>MemoryRegionSection</code>就像是为<code>FlatRange</code>数组设置的一种中介表示，便于传入<code>KVM</code>，因为传入<code>KVM</code>应该是对平坦内存的一种表示】，并注册到 <code>KVM</code> 中：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">listener_add_address_space</span><span class="p">(</span><span class="n">MemoryListener</span> <span class="o">*</span><span class="n">listener</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                                       <span class="n">AddressSpace</span> <span class="o">*</span><span class="n">as</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">FlatView</span> <span class="o">*</span><span class="n">view</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">FlatRange</span> <span class="o">*</span><span class="n">fr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="o">-&gt;</span><span class="n">begin</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">listener</span><span class="o">-&gt;</span><span class="nf">begin</span><span class="p">(</span><span class="n">listener</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* 开启内存脏页记录 */</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">global_dirty_tracking</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="o">-&gt;</span><span class="n">log_global_start</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">listener</span><span class="o">-&gt;</span><span class="nf">log_global_start</span><span class="p">(</span><span class="n">listener</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* 遍历 AddressSpace 对应的 FlatRange 数组，并将其转换成 MemoryRegionSection */</span>
</span></span><span class="line"><span class="cl">    <span class="n">view</span> <span class="o">=</span> <span class="nf">address_space_get_flatview</span><span class="p">(</span><span class="n">as</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">FOR_EACH_FLAT_RANGE</span><span class="p">(</span><span class="n">fr</span><span class="p">,</span> <span class="n">view</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">MemoryRegionSection</span> <span class="n">section</span> <span class="o">=</span> <span class="nf">section_from_flat_range</span><span class="p">(</span><span class="n">fr</span><span class="p">,</span> <span class="n">view</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/* 将 section 所代表的内存区域注册到 KVM 中 */</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="o">-&gt;</span><span class="n">region_add</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">listener</span><span class="o">-&gt;</span><span class="nf">region_add</span><span class="p">(</span><span class="n">listener</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">section</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">fr</span><span class="o">-&gt;</span><span class="n">dirty_log_mask</span> <span class="o">&amp;&amp;</span> <span class="n">listener</span><span class="o">-&gt;</span><span class="n">log_start</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">listener</span><span class="o">-&gt;</span><span class="nf">log_start</span><span class="p">(</span><span class="n">listener</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">section</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">fr</span><span class="o">-&gt;</span><span class="n">dirty_log_mask</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="o">-&gt;</span><span class="n">commit</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">listener</span><span class="o">-&gt;</span><span class="nf">commit</span><span class="p">(</span><span class="n">listener</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">flatview_unref</span><span class="p">(</span><span class="n">view</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>由于此时 <code>AddressSapce</code> 尚未初始化，所以此处的循环为空，仅是在全局注册了<code>kvm_memory_listener</code>。最后调用了<code>kvm_memory_listener-&gt;region_add()</code>，对应的实现是<code>kvm_region_add()</code>，该函数最终会通过<code>ioctl(KVM_SET_USER_MEMORY_REGION)</code>，将 <code>QEMU</code> 侧申请的内存信息传入 <code>KVM</code> 进行注册，这里的流程会在下一部分进行分析。</p>
<h3 id="addressspace-的初始化">AddressSpace 的初始化</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125154841.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220125154841.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="err">└─</span> <span class="kt">void</span> <span class="nf">cpu_exec_init_all</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">       <span class="err">├─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">memory_map_init</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="err">├─</span> <span class="kt">void</span> <span class="nf">memory_region_init</span><span class="p">()</span>    <span class="c1">// 初始化 system_memory/io 这两个全局 MemoryRegion
</span></span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="err">├─</span> <span class="kt">void</span> <span class="nf">set_system_memory_map</span><span class="p">()</span> <span class="c1">// address_space_memory-&gt;root = system_memory
</span></span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="o">|</span>    <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">memory_region_update_topology</span><span class="p">()</span>        <span class="c1">// 为 MemoryRegion 生成 FlatView
</span></span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="o">|</span>         <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">address_space_update_topology</span><span class="p">()</span>   <span class="c1">// as-&gt;current_map = new_view
</span></span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="o">|</span>              <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">address_space_update_topology_pass</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="o">|</span>                   <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">kvm_region_add</span><span class="p">()</span>        <span class="c1">// region_add 对应的回调实现
</span></span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="o">|</span>                        <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">kvm_set_phys_mem</span><span class="p">()</span> <span class="c1">// 根据传入的 section 填充 KVMSlot
</span></span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="o">|</span>                             <span class="err">└─</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">kvm_set_user_memory_region</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="o">|</span>                                  <span class="err">└─</span> <span class="kt">int</span> <span class="nf">ioctl</span><span class="p">(</span><span class="n">KVM_SET_USER_MEMORY_REGION</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="o">|</span>
</span></span><span class="line"><span class="cl">       <span class="o">|</span>    <span class="err">└─</span> <span class="kt">void</span> <span class="nf">memory_listener_register</span><span class="p">()</span> <span class="c1">// 注册对应的 MemoryListener
</span></span></span><span class="line"><span class="cl">       <span class="o">|</span>         <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">listener_add_address_space</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">       <span class="o">|</span>
</span></span><span class="line"><span class="cl">       <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">io_mem_init</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="err">└─</span> <span class="kt">void</span> <span class="nf">memory_region_init_io</span><span class="p">()</span> <span class="c1">// ram/rom/unassigned/notdirty/subpage-ram/watch
</span></span></span><span class="line"><span class="cl">                 <span class="err">└─</span> <span class="kt">void</span> <span class="nf">memory_region_init</span><span class="p">()</span>
</span></span></code></pre></div><p>第一部分在全局注册了<code>kvm_memory_listener</code>，但由于<code>AddressSpace</code> 尚未初始化，实际上并未向 <code>KVM</code> 中注册任何实际的内存信息。<code>QEMU</code> 在<code>main()</code>函数中会继续调用<code>cpu_exec_init_all()</code>对<code>AddressSpace</code>进行初始化，该函数实际上是对两个 <code>init</code> 函数的封装调用：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">cpu_exec_init_all</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">qemu_mutex_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ram_list</span><span class="p">.</span><span class="n">mutex</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* The data structures we set up here depend on knowing the page size,
</span></span></span><span class="line"><span class="cl"><span class="cm">     * so no more changes can be made after this point.
</span></span></span><span class="line"><span class="cl"><span class="cm">     * In an ideal world, nothing we did before we had finished the
</span></span></span><span class="line"><span class="cl"><span class="cm">     * machine setup would care about the target page size, and we could
</span></span></span><span class="line"><span class="cl"><span class="cm">     * do this much later, rather than requiring board models to state
</span></span></span><span class="line"><span class="cl"><span class="cm">     * up front what their requirements are.
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">finalize_target_page_bits</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nf">io_mem_init</span><span class="p">();</span>      <span class="c1">// 初始化六个I/O MemoryRegion
</span></span></span><span class="line"><span class="cl">    <span class="nf">memory_map_init</span><span class="p">();</span> <span class="c1">// 初始化两个全局 AddressSpace，以及对应的 MemoryRegion、FlatView
</span></span></span><span class="line"><span class="cl">    <span class="nf">qemu_mutex_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">map_client_list_lock</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>先来看<code>memory_map_init()</code>，主要用来初始化两个全局的系统地址空间<code>system_memory</code>、<code>system_io</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">memory_map_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">system_memory</span> <span class="o">=</span> <span class="nf">g_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">system_memory</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 1. 初始化 system_memory
</span></span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init</span><span class="p">(</span><span class="n">system_memory</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="s">&#34;system&#34;</span><span class="p">,</span> <span class="n">UINT64_MAX</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 2. 设置 address_space_memory 关联 system_memory
</span></span></span><span class="line"><span class="cl">    <span class="c1">// 这两个都是全局变量，也就是把内存地址空间和 IO 地址空间于对应的 MemoryRegion 联系起来 
</span></span></span><span class="line"><span class="cl">    <span class="c1">//及其对应的 FlatView
</span></span></span><span class="line"><span class="cl">    <span class="nf">address_space_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">address_space_memory</span><span class="p">,</span> <span class="n">system_memory</span><span class="p">,</span> <span class="s">&#34;memory&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">system_io</span> <span class="o">=</span> <span class="nf">g_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">system_io</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 1. 初始化 system_io  
</span></span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init_io</span><span class="p">(</span><span class="n">system_io</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">unassigned_io_ops</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="s">&#34;io&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                          <span class="mi">65536</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 2. 设置 address_space_io 关联 system_io 
</span></span></span><span class="line"><span class="cl">    <span class="c1">// 及其对应的 FlatView
</span></span></span><span class="line"><span class="cl">    <span class="nf">address_space_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">address_space_io</span><span class="p">,</span> <span class="n">system_io</span><span class="p">,</span> <span class="s">&#34;I/O&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这里比较重要的是<code>address_space_init()</code>，先设置 <code>AddressSpace</code> 对应的 <code>MemoryRegion</code>，之后根据<code>system_memory</code>更新<code>address_space_memory</code>对应的 <code>FlatView</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">address_space_init</span><span class="p">(</span><span class="n">AddressSpace</span> <span class="o">*</span><span class="n">as</span><span class="p">,</span> <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">root</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">memory_region_ref</span><span class="p">(</span><span class="n">root</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 将 address_space_memory 的 root 域指向 system_memory
</span></span></span><span class="line"><span class="cl">    <span class="n">as</span><span class="o">-&gt;</span><span class="n">root</span> <span class="o">=</span> <span class="n">root</span><span class="p">;</span>        
</span></span><span class="line"><span class="cl">    <span class="n">as</span><span class="o">-&gt;</span><span class="n">current_map</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">as</span><span class="o">-&gt;</span><span class="n">ioeventfd_nb</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">as</span><span class="o">-&gt;</span><span class="n">ioeventfds</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_INIT</span><span class="p">(</span><span class="o">&amp;</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">listeners</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_INSERT_TAIL</span><span class="p">(</span><span class="o">&amp;</span><span class="n">address_spaces</span><span class="p">,</span> <span class="n">as</span><span class="p">,</span> <span class="n">address_spaces_link</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">as</span><span class="o">-&gt;</span><span class="n">name</span> <span class="o">=</span> <span class="nf">g_strdup</span><span class="p">(</span><span class="n">name</span> <span class="o">?</span> <span class="nl">name</span> <span class="p">:</span> <span class="s">&#34;anonymous&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 根据 system_memory 更新 address_space_memory 对应的 FlatView
</span></span></span><span class="line"><span class="cl">    <span class="nf">address_space_update_topology</span><span class="p">(</span><span class="n">as</span><span class="p">);</span>  
</span></span><span class="line"><span class="cl">    <span class="nf">address_space_update_ioeventfds</span><span class="p">(</span><span class="n">as</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>address_space_update_topology()</code>会继续调用<code>generate_memory_topology()</code>生成 <code>AddressSpace</code> 对应的 <code>FlatView</code>视图：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">address_space_update_topology</span><span class="p">(</span><span class="n">AddressSpace</span> <span class="o">*</span><span class="n">as</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">physmr</span> <span class="o">=</span> <span class="nf">memory_region_get_flatview_root</span><span class="p">(</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">root</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">flatviews_init</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">g_hash_table_lookup</span><span class="p">(</span><span class="n">flat_views</span><span class="p">,</span> <span class="n">physmr</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">generate_memory_topology</span><span class="p">(</span><span class="n">physmr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">address_space_set_flatview</span><span class="p">(</span><span class="n">as</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>address_space_update_topology()</code>会先调用<code>generate_memory_topology()</code>生成<code>system_memory</code>更新后的视图<code>new_view</code>，再将<code>address_space_memory</code>的<code>current_map</code>指向这个<code>new_view</code>，最后销毁<code>old_view</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">address_space_set_flatview</span><span class="p">(</span><span class="n">AddressSpace</span> <span class="o">*</span><span class="n">as</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">FlatView</span> <span class="o">*</span><span class="n">old_view</span> <span class="o">=</span> <span class="nf">address_space_to_flatview</span><span class="p">(</span><span class="n">as</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">physmr</span> <span class="o">=</span> <span class="nf">memory_region_get_flatview_root</span><span class="p">(</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">root</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">FlatView</span> <span class="o">*</span><span class="n">new_view</span> <span class="o">=</span> <span class="nf">g_hash_table_lookup</span><span class="p">(</span><span class="n">flat_views</span><span class="p">,</span> <span class="n">physmr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">assert</span><span class="p">(</span><span class="n">new_view</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">old_view</span> <span class="o">==</span> <span class="n">new_view</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">old_view</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">flatview_ref</span><span class="p">(</span><span class="n">old_view</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">flatview_ref</span><span class="p">(</span><span class="n">new_view</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">QTAILQ_EMPTY</span><span class="p">(</span><span class="o">&amp;</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">listeners</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">FlatView</span> <span class="n">tmpview</span> <span class="o">=</span> <span class="p">{</span> <span class="p">.</span><span class="n">nr</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">},</span> <span class="o">*</span><span class="n">old_view2</span> <span class="o">=</span> <span class="n">old_view</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">old_view2</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">old_view2</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">tmpview</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nf">address_space_update_topology_pass</span><span class="p">(</span><span class="n">as</span><span class="p">,</span> <span class="n">old_view2</span><span class="p">,</span> <span class="n">new_view</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">address_space_update_topology_pass</span><span class="p">(</span><span class="n">as</span><span class="p">,</span> <span class="n">old_view2</span><span class="p">,</span> <span class="n">new_view</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Writes are protected by the BQL.  */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">qatomic_rcu_set</span><span class="p">(</span><span class="o">&amp;</span><span class="n">as</span><span class="o">-&gt;</span><span class="n">current_map</span><span class="p">,</span> <span class="n">new_view</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">old_view</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">flatview_unref</span><span class="p">(</span><span class="n">old_view</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Note that all the old MemoryRegions are still alive up to this
</span></span></span><span class="line"><span class="cl"><span class="cm">     * point.  This relieves most MemoryListeners from the need to
</span></span></span><span class="line"><span class="cl"><span class="cm">     * ref/unref the MemoryRegions they get---unless they use them
</span></span></span><span class="line"><span class="cl"><span class="cm">     * outside the iothread mutex, in which case precise reference
</span></span></span><span class="line"><span class="cl"><span class="cm">     * counting is necessary.
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">old_view</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">flatview_unref</span><span class="p">(</span><span class="n">old_view</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在<code>address_space_update_topology_pass()</code>的最后，会调用<code>MEMORY_LISTENER_UPDATE_REGION</code>这个宏，触发<code>region_add</code>对应的回调函数<code>kvm_region_add()</code>。</p>
<p>这个宏在<code>memory.c</code>中定义，会将 <code>FlatView</code> 中的 <code>FlatRange</code> 转换为 <code>MemoryRegionSection</code>，作为入参传递给<code>kvm_region_add()</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="cm">/* No need to ref/unref .mr, the FlatRange keeps it alive.  */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...)  \
</span></span></span><span class="line"><span class="cl"><span class="cp">    do {                                                                \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MemoryRegionSection mrs = section_from_flat_range(fr,           \
</span></span></span><span class="line"><span class="cl"><span class="cp">                address_space_to_flatview(as));                         \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MEMORY_LISTENER_CALL(as, callback, dir, &amp;mrs, ##_args);         \
</span></span></span><span class="line"><span class="cl"><span class="cp">    } while(0)
</span></span></span></code></pre></div><p>而<code>kvm_region_add()</code>实际上是对<code>kvm_set_phys_mem()</code>的封装调用。该函数比较复杂，会根据传入的<code>section</code>填充 KVMSlot，再传递给<code>kvm_set_user_memory_region()</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">kvm_set_user_memory_region</span><span class="p">(</span><span class="n">KVMMemoryListener</span> <span class="o">*</span><span class="n">kml</span><span class="p">,</span> <span class="n">KVMSlot</span> <span class="o">*</span><span class="n">slot</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">new</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">KVMState</span> <span class="o">*</span><span class="n">s</span> <span class="o">=</span> <span class="n">kvm_state</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">kvm_userspace_memory_region</span> <span class="n">mem</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 根据 KVMSlot 填充 kvm_userspace_memory_region
</span></span></span><span class="line"><span class="cl">    <span class="n">mem</span><span class="p">.</span><span class="n">slot</span> <span class="o">=</span> <span class="n">slot</span><span class="o">-&gt;</span><span class="n">slot</span> <span class="o">|</span> <span class="p">(</span><span class="n">kml</span><span class="o">-&gt;</span><span class="n">as_id</span> <span class="o">&lt;&lt;</span> <span class="mi">16</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">mem</span><span class="p">.</span><span class="n">guest_phys_addr</span> <span class="o">=</span> <span class="n">slot</span><span class="o">-&gt;</span><span class="n">start_addr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mem</span><span class="p">.</span><span class="n">userspace_addr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="p">)</span><span class="n">slot</span><span class="o">-&gt;</span><span class="n">ram</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mem</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="n">slot</span><span class="o">-&gt;</span><span class="n">flags</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">slot</span><span class="o">-&gt;</span><span class="n">memory_size</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">new</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">mem</span><span class="p">.</span><span class="n">flags</span> <span class="o">^</span> <span class="n">slot</span><span class="o">-&gt;</span><span class="n">old_flags</span><span class="p">)</span> <span class="o">&amp;</span> <span class="n">KVM_MEM_READONLY</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/* Set the slot size to 0 before setting the slot to the desired
</span></span></span><span class="line"><span class="cl"><span class="cm">         * value. This is needed based on KVM commit 75d61fbc. */</span>
</span></span><span class="line"><span class="cl">        <span class="n">mem</span><span class="p">.</span><span class="n">memory_size</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">ret</span> <span class="o">=</span> <span class="nf">kvm_vm_ioctl</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">KVM_SET_USER_MEMORY_REGION</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mem</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">goto</span> <span class="n">err</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">mem</span><span class="p">.</span><span class="n">memory_size</span> <span class="o">=</span> <span class="n">slot</span><span class="o">-&gt;</span><span class="n">memory_size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ret</span> <span class="o">=</span> <span class="nf">kvm_vm_ioctl</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">KVM_SET_USER_MEMORY_REGION</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mem</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">slot</span><span class="o">-&gt;</span><span class="n">old_flags</span> <span class="o">=</span> <span class="n">mem</span><span class="p">.</span><span class="n">flags</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>可以看到这里又将 <code>KVMSlot</code> 转换为 <code>kvm_userspace_memory_region</code>，作为<code>ioctl()</code>的参数，交给内核中的 <code>KVM</code> 进行内存的注册【设置<code>GPA-&gt;HVA</code>的映射关系，在内核空间维护并管理 Guest 的内存】。</p>
<p>至此 QEMU 侧负责管理内存的数据结构均已完成初始化，<strong>可以参考下面的图片了解各数据结构之间的对应关系</strong></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127155506.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127155506.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="实际内存的分配">实际内存的分配</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127160121.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127160121.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="err">└─</span> <span class="kt">void</span> <span class="n">machine</span><span class="o">-&gt;</span><span class="nf">init</span><span class="p">(</span><span class="n">ram_size</span><span class="p">,</span> <span class="p">...)</span>
</span></span><span class="line"><span class="cl">       <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">pc_init_pci</span><span class="p">(</span><span class="n">ram_size</span><span class="p">,</span> <span class="p">...)</span> <span class="c1">// 初始化虚拟机
</span></span></span><span class="line"><span class="cl">            <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">pc_init1</span><span class="p">(</span><span class="n">system_memory</span><span class="p">,</span> <span class="n">system_io</span><span class="p">,</span> <span class="n">ram_size</span><span class="p">,</span> <span class="p">...)</span>
</span></span><span class="line"><span class="cl">                 <span class="err">├─</span> <span class="kt">void</span> <span class="nf">memory_region_init</span><span class="p">(</span><span class="n">pci_memory</span><span class="p">,</span> <span class="s">&#34;pci&#34;</span><span class="p">,</span> <span class="p">...)</span> <span class="c1">// pci_memory, rom_memory
</span></span></span><span class="line"><span class="cl">                 <span class="err">└─</span> <span class="kt">void</span> <span class="nf">pc_memory_init</span><span class="p">()</span> <span class="c1">// 初始化内存，分配实际的物理内存地址
</span></span></span><span class="line"><span class="cl">                      <span class="err">├─</span> <span class="kt">void</span> <span class="nf">memory_region_init_ram</span><span class="p">()</span> <span class="c1">// 创建 pc.ram, pc.rom 并分配内存
</span></span></span><span class="line"><span class="cl">                      <span class="o">|</span>    <span class="err">├─</span> <span class="kt">void</span> <span class="nf">memory_region_init</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                      <span class="o">|</span>    <span class="err">└─</span> <span class="kt">ram_addr_t</span> <span class="nf">qemu_ram_alloc</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                      <span class="o">|</span>         <span class="err">└─</span> <span class="kt">ram_addr_t</span> <span class="nf">qemu_ram_alloc_from_ptr</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                      <span class="o">|</span>
</span></span><span class="line"><span class="cl">                      <span class="err">├─</span> <span class="kt">void</span> <span class="nf">vmstate_register_ram_global</span><span class="p">()</span> <span class="c1">// 将 MR 的 name 写入 RAMBlock 的 idstr
</span></span></span><span class="line"><span class="cl">                      <span class="o">|</span>    <span class="err">└─</span> <span class="kt">void</span> <span class="nf">vmstate_register_ram</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                      <span class="o">|</span>         <span class="err">└─</span> <span class="kt">void</span> <span class="nf">qemu_ram_set_idstr</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                      <span class="o">|</span>
</span></span><span class="line"><span class="cl">                      <span class="err">├─</span> <span class="kt">void</span> <span class="nf">memory_region_init_alias</span><span class="p">()</span>    <span class="c1">// 初始化 ram_below_4g, ram_above_4g
</span></span></span><span class="line"><span class="cl">                      <span class="err">└─</span> <span class="kt">void</span> <span class="nf">memory_region_add_subregion</span><span class="p">()</span> <span class="c1">// 在 system_memory 中添加 subregions
</span></span></span><span class="line"><span class="cl">                           <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">memory_region_add_subregion_common</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                                <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">memory_region_update_topology</span><span class="p">()</span> <span class="c1">// 为 MemoryRegion 生成 FlatView
</span></span></span><span class="line"><span class="cl">                                     <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">address_space_update_topology</span><span class="p">()</span> <span class="c1">// as-&gt;current_map = new_view
</span></span></span><span class="line"><span class="cl">                                          <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">address_space_update_topology_pass</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                                               <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">kvm_region_add</span><span class="p">()</span> <span class="c1">// region_add 对应的回调实现
</span></span></span><span class="line"><span class="cl">                                                    <span class="err">└─</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">kvm_set_phys_mem</span><span class="p">()</span> <span class="c1">// 根据传入的 section 填充 KVMSlot
</span></span></span><span class="line"><span class="cl">                                                         <span class="err">└─</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">kvm_set_user_memory_region</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">                                                              <span class="err">└─</span> <span class="kt">int</span> <span class="nf">ioctl</span><span class="p">(</span><span class="n">KVM_SET_USER_MEMORY_REGION</span><span class="p">)</span>
</span></span></code></pre></div><p>之前的回调函数注册、AddressSpace 的初始化，实际上均没有对应的物理内存。【实际的内存是在 RAMBlock 中】</p>
<p>我们再回到 <code>qemu</code> 启动的 <code>main</code> 函数中。接下来的初始化过程会调用 <code>pc_init1</code>。在这里面，对于 <code>CPU</code> 虚拟化，我们会调用 <code>pc_cpus_init</code>。另外，<code>pc_init1</code> 还会调用<code>pc_memory_init</code>，进行内存的虚拟化。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="nf">pc_memory_init</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">system_memory</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kernel_filename</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kernel_cmdline</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">initrd_filename</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="kt">ram_addr_t</span> <span class="n">below_4g_mem_size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="kt">ram_addr_t</span> <span class="n">above_4g_mem_size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">rom_memory</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="n">MemoryRegion</span> <span class="o">**</span><span class="n">ram_memory</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">ram</span><span class="p">,</span> <span class="o">*</span><span class="n">option_rom_mr</span><span class="p">;</span>         <span class="c1">// 两个实体 MR: pc.ram, pc.rom
</span></span></span><span class="line"><span class="cl">    <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">ram_below_4g</span><span class="p">,</span> <span class="o">*</span><span class="n">ram_above_4g</span><span class="p">;</span> <span class="c1">// 两个别名 MR: ram_below_4g, ram_above_4g
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="cm">/* Allocate RAM.  We allocate it as a single memory region and use
</span></span></span><span class="line"><span class="cl"><span class="cm">     * aliases to address portions of it, mostly for backwards compatibility
</span></span></span><span class="line"><span class="cl"><span class="cm">     * with older qemus that used qemu_ram_alloc().
</span></span></span><span class="line"><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="cl">    <span class="n">ram</span> <span class="o">=</span> <span class="nf">g_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">ram</span><span class="p">));</span> <span class="c1">// 创建 ram
</span></span></span><span class="line"><span class="cl">    <span class="c1">// 分配具体的内存（实际上会创建一个 RAMBlock 并将其 offset 值写入 ram.ram_addr，对应 GPA）
</span></span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init_ram</span><span class="p">(</span><span class="n">ram</span><span class="p">,</span> <span class="s">&#34;pc.ram&#34;</span><span class="p">,</span> <span class="n">below_4g_mem_size</span> <span class="o">+</span> <span class="n">above_4g_mem_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 将 MR 的 name 写入 RAMBlock 的 idstr
</span></span></span><span class="line"><span class="cl">    <span class="nf">vmstate_register_ram_global</span><span class="p">(</span><span class="n">ram</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="n">ram_memory</span> <span class="o">=</span> <span class="n">ram</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 创建 ram_below_4g 表示 4G 以下的内存
</span></span></span><span class="line"><span class="cl">    <span class="n">ram_below_4g</span> <span class="o">=</span> <span class="nf">g_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">ram_below_4g</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init_alias</span><span class="p">(</span><span class="n">ram_below_4g</span><span class="p">,</span> <span class="s">&#34;ram-below-4g&#34;</span><span class="p">,</span> <span class="n">ram</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">below_4g_mem_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 将 ram_below_4g 挂在 system_memory 下
</span></span></span><span class="line"><span class="cl">    <span class="nf">memory_region_add_subregion</span><span class="p">(</span><span class="n">system_memory</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ram_below_4g</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">above_4g_mem_size</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ram_above_4g</span> <span class="o">=</span> <span class="nf">g_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">ram_above_4g</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">        <span class="nf">memory_region_init_alias</span><span class="p">(</span><span class="n">ram_above_4g</span><span class="p">,</span> <span class="s">&#34;ram-above-4g&#34;</span><span class="p">,</span> <span class="n">ram</span><span class="p">,</span> <span class="n">below_4g_mem_size</span><span class="p">,</span> <span class="n">above_4g_mem_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">memory_region_add_subregion</span><span class="p">(</span><span class="n">system_memory</span><span class="p">,</span> <span class="mh">0x100000000ULL</span><span class="p">,</span> <span class="n">ram_above_4g</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* ... */</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这里的重点在于<code>memory_region_init_ram()</code>，它通过<code>qemu_ram_alloc()</code>获取 ram 这个 <code>MemoryRegion</code> 对应的 <code>RAMBlock</code> 的<code>offset</code>，并存入<code>ram.ram_addr</code>，这样就可以在<code>ram_list</code>中根据该字段查找 <code>MR</code> 对应的 <code>RAMBlock</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">memory_region_init_ram</span><span class="p">(</span><span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">size</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">memory_region_init</span><span class="p">(</span><span class="n">mr</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span> <span class="c1">// 填充字段，初始化默认值
</span></span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">ram</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// 表示为 RAM
</span></span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">terminates</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> <span class="c1">// 表示为实体 MemoryRegion
</span></span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">destructor</span> <span class="o">=</span> <span class="n">memory_region_destructor_ram</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mr</span><span class="o">-&gt;</span><span class="n">ram_addr</span> <span class="o">=</span> <span class="nf">qemu_ram_alloc</span><span class="p">(</span><span class="n">size</span><span class="p">,</span> <span class="n">mr</span><span class="p">);</span> <span class="c1">// 这里保存 RAMBlock 的 offset，即 GPA
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>而 qemu_ram_alloc() 最终会调用 qemu_ram_alloc_from_ptr()，创建一个对应大小 RAMBlock 并分配内存，返回对应的 GPA 地址存入 mr-&gt;ram_addr 中：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="kt">ram_addr_t</span> <span class="nf">qemu_ram_alloc_from_ptr</span><span class="p">(</span><span class="kt">ram_addr_t</span> <span class="n">size</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">host</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                                   <span class="n">MemoryRegion</span> <span class="o">*</span><span class="n">mr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">RAMBlock</span> <span class="o">*</span><span class="n">new_block</span><span class="p">;</span> <span class="c1">// 创建一个 RAMBlock
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">size</span> <span class="o">=</span> <span class="nf">TARGET_PAGE_ALIGN</span><span class="p">(</span><span class="n">size</span><span class="p">);</span> <span class="c1">// 页对齐
</span></span></span><span class="line"><span class="cl">    <span class="n">new_block</span> <span class="o">=</span> <span class="nf">g_malloc0</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">new_block</span><span class="p">));</span> <span class="c1">// 初始化 new_block
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">mr</span> <span class="o">=</span> <span class="n">mr</span><span class="p">;</span> <span class="c1">// 将 new_block-&gt; 指向入参的 MemoryRegion
</span></span></span><span class="line"><span class="cl">    <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">offset</span> <span class="o">=</span> <span class="nf">find_ram_offset</span><span class="p">(</span><span class="n">size</span><span class="p">);</span> <span class="c1">// 从 ram_list 中的 RAMBlock 之间找到一段可以满足 size 需求的 gap，并返回起始地址的 offset，对应 GPA
</span></span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">host</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 新建的 RAMBlock host 字段为空，跳过
</span></span></span><span class="line"><span class="cl">        <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span> <span class="o">=</span> <span class="n">host</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">flags</span> <span class="o">|=</span> <span class="n">RAM_PREALLOC_MASK</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">mem_path</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 未指定 mem_path
</span></span></span><span class="line"><span class="cl"><span class="cp">#if defined (__linux__) &amp;&amp; !defined(TARGET_S390X)
</span></span></span><span class="line"><span class="cl">            <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span> <span class="o">=</span> <span class="nf">file_ram_alloc</span><span class="p">(</span><span class="n">new_block</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">mem_path</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span> <span class="o">=</span> <span class="nf">qemu_vmalloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="nf">qemu_madvise</span><span class="p">(</span><span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">QEMU_MADV_MERGEABLE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl">            <span class="nf">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;-mem-path option unsupported</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="nf">xen_enabled</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nf">xen_ram_alloc</span><span class="p">(</span><span class="n">new_block</span><span class="o">-&gt;</span><span class="n">offset</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">mr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nf">kvm_enabled</span><span class="p">())</span> <span class="p">{</span> <span class="c1">// 从这里继续
</span></span></span><span class="line"><span class="cl">                <span class="cm">/* some s390/kvm configurations have special constraints */</span>
</span></span><span class="line"><span class="cl">                <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span> <span class="o">=</span> <span class="nf">kvm_vmalloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span> <span class="c1">// 实际上还是调用 qemu_vmalloc(size)
</span></span></span><span class="line"><span class="cl">            <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span> <span class="o">=</span> <span class="nf">qemu_vmalloc</span><span class="p">(</span><span class="n">size</span><span class="p">);</span> <span class="c1">// 从 QEMU 的线性空间中分配 size 大小的内存，返回 HVA
</span></span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nf">qemu_madvise</span><span class="p">(</span><span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">QEMU_MADV_MERGEABLE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">length</span> <span class="o">=</span> <span class="n">size</span><span class="p">;</span> <span class="c1">// 将 length 设置为 size
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">QLIST_INSERT_HEAD</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ram_list</span><span class="p">.</span><span class="n">blocks</span><span class="p">,</span> <span class="n">new_block</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span> <span class="c1">// 将该 RAMBlock 插入 ram_list 头部
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ram_list</span><span class="p">.</span><span class="n">phys_dirty</span> <span class="o">=</span> <span class="nf">g_realloc</span><span class="p">(</span><span class="n">ram_list</span><span class="p">.</span><span class="n">phys_dirty</span><span class="p">,</span> <span class="c1">// 重新分配 ram_list.phys_dirty 的内存空间
</span></span></span><span class="line"><span class="cl">                                       <span class="nf">last_ram_offset</span><span class="p">()</span> <span class="o">&gt;&gt;</span> <span class="n">TARGET_PAGE_BITS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">memset</span><span class="p">(</span><span class="n">ram_list</span><span class="p">.</span><span class="n">phys_dirty</span> <span class="o">+</span> <span class="p">(</span><span class="n">new_block</span><span class="o">-&gt;</span><span class="n">offset</span> <span class="o">&gt;&gt;</span> <span class="n">TARGET_PAGE_BITS</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">           <span class="mi">0</span><span class="p">,</span> <span class="n">size</span> <span class="o">&gt;&gt;</span> <span class="n">TARGET_PAGE_BITS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">cpu_physical_memory_set_dirty_range</span><span class="p">(</span><span class="n">new_block</span><span class="o">-&gt;</span><span class="n">offset</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="mh">0xff</span><span class="p">);</span> <span class="c1">// 对该 RAMBlock 对应的内存标记为 dirty
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">qemu_ram_setup_dump</span><span class="p">(</span><span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">kvm_enabled</span><span class="p">())</span>
</span></span><span class="line"><span class="cl">        <span class="nf">kvm_setup_guest_memory</span><span class="p">(</span><span class="n">new_block</span><span class="o">-&gt;</span><span class="n">host</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">new_block</span><span class="o">-&gt;</span><span class="n">offset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这样一来<code>ram</code>【其实就是<code>system memory</code>，整个<code>Guest</code>物理空间的大小】对应的 <code>RAMBlock</code> 中就分配好了 <code>GPA</code> 和 <code>HVA</code>，就可以<strong>将内存信息同步至 KVM 侧</strong>了。</p>
<p>最后回到<code>pc_memory_init()</code>中，在分配完实际内存后，会先调用<code>memory_region_init_alias()</code>初始化<code>ram_below_4g</code>、<code>ram_above_4g</code>这两个<code>alias</code>，之后调用<code>memory_region_add_subregion()</code>将这两个 <code>alias</code> 指向<code>ram</code>这个实体 <code>MemoryRegion</code>。如下图，该函数最终会触发<code>kvm_region_add()</code>回调，将实际的内存信息传入 <code>KVM</code> 注册。该过程如下图所示，与之前分析的流程相同，此处不再赘述。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127163205.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127163205.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="总结">总结</h2>
<p>虚拟机的内存管理也是需要用户态的 <code>qemu</code> 和内核态的 <code>KVM</code> 共同完成。为了加速内存映射，需要借助硬件的 <code>EPT</code> 技术。</p>
<h3 id="qemu-侧">QEMU 侧</h3>
<ul>
<li>
<p>创建一系列 <code>MemoryRegion</code>，分别表示 <code>Guest</code> 中的 <code>RAM</code>、<code>ROM</code> 等区域。<code>MemoryRegion</code>之间通过 <code>alias</code> 或 <code>subregions</code> 的方式维护相互之间的关系，从而进一步细化区域的定义</p>
</li>
<li>
<p>对于一个实体 <code>MemoryRegion</code>（非 <code>alias</code>），在初始化内存的过程中 <code>QEMU</code> 会创建它所对应的 <code>RAMBlock</code>。该 <code>RAMBlock</code> 通过调用<code>qemu_ram_alloc_from_ptr()</code>从 <code>QEMU</code> 的进程地址空间中<strong>以 mmap 的方式分配内存</strong>，并负责<strong>维护该 MemoryRegion 对应内存的起始 GPA/HVA/size 等相关信息</strong>【在<code>qemu_ram_alloc_from_ptr</code>中创建的新<code>RAMBlock</code>有<code>offset</code>、<code>host</code>的赋值，即<code>GPA-&gt;HVA</code>的对应关系】</p>
</li>
<li>
<p><code>AddressSpace</code> 表示 <code>Guest</code> 的物理地址空间。如果 <code>AddressSpace</code> 中的 <code>MemoryRegion</code> 发生变化，则注册的 <code>listener</code> 会被触发，将所属的 <code>MemoryRegion</code> 树展开生成一维的 <code>FlatView</code>，比较 FlatRange 是否发生了变化。如果是，则调用相应的方法对 <code>MemoryRegionSection</code> 进行检查，更新 <code>QEMU</code> 中的 <code>KVMSlot</code>，同时填充<code>kvm_userspace_memory_region</code>结构体，作为<code>ioctl()</code>的参数更新 <code>KVM</code> 中的<code>kvm_memory_slot</code></p>
</li>
</ul>
<h3 id="kvm-侧">KVM 侧</h3>
<ul>
<li>
<p>当 <code>QEMU</code> 通过<code>ioctl()</code>创建 <code>vcpu</code> 时，调用<code>kvm_mmu_create()</code>初始化 <code>MMU</code> 相关信息。
当 <code>KVM</code> 要进入 <code>Guest</code> 前，<code>vcpu_enter_guest()=&gt;kvm_mmu_reload()</code>会将根级页表地址加载到 <code>VMCS</code>，让 <code>Guest</code> 使用该页表</p>
</li>
<li>
<p>当发生<code>EPT Violation</code> 时，<code>VM-EXIT</code>到 <code>KVM</code> 中。如果是缺页，则根据 <code>GPA</code> 算出 <code>gfn</code>，再根据 <code>gfn</code> 找到对应的 <code>KVMSlot</code>，从中得到对应的 <code>HVA</code>。然后根据 <code>HVA</code> 算出对应的 <code>pfn</code>，确保该 <code>Page</code> 位于内存中。填好缺失的页之后，需要更新 <code>EPT</code>，完善其中缺少的页表项，逐层补全页表</p>
</li>
</ul>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127163418.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127163418.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<blockquote>
<p>虚拟机的物理内存空间里面的页面当然不是一开始就映射到物理页面的，只有当虚拟机的内存被访问的时候，也即 <code>mmap</code> 分配的虚拟内存空间被访问的时候，先查看 <code>EPT</code> 页表，是否已经映射过，如果已经映射过，则经过四级页表映射，就能访问到物理页面。
如果没有映射过，则虚拟机会通过<code>VM-Exit</code>指令回到宿主机模式，通过 <code>handle_ept_violation</code> 补充页表映射。先是通过 <code>handle_mm_fault</code>为虚拟机的物理内存空间分配真正的物理页面，然后通过 <code>__direct_map</code> 添加 <code>EPT</code> 页表映射。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127171031.jpg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220127171031.jpg" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
</blockquote>
<h2 id="reference">Reference</h2>
<p><a href="http://xudaxian.fun/2020/09/03/QEMU%E5%86%85%E5%AD%98%E7%A9%BA%E9%97%B4%E8%99%9A%E6%8B%9F%E5%8C%96%E5%8F%8A%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/">“QEMU 内存空间虚拟化及内存管理” - B10g | FΓom 许大仙</a>
<a href="https://www.cnblogs.com/LoyenWang/p/13943005.html">【原创】Linux 虚拟化 KVM-Qemu 分析（五）之内存虚拟化 - LoyenWang - 博客园</a>
<a href="https://blog.csdn.net/xiongwenwu/article/details/58586013">KVM/Qemu 工作原理系列目录_xiongwenwu 的专栏-CSDN 博客_qemu 目录结构</a>
<a href="https://abelsu7.top/2019/07/07/kvm-memory-virtualization/">QEMU 内存虚拟化源码分析 | Keep Coding | 苏易北</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 帧缓冲</title>
      <link>https://lifeislife.cn/posts/linux%E5%B8%A7%E7%BC%93%E5%86%B2/</link>
      <pubDate>Mon, 17 Jan 2022 17:38:04 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E5%B8%A7%E7%BC%93%E5%86%B2/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;
&lt;p&gt;FrameBuffer 是内核当中的一种驱动程序接口。Linux 是工作在保护模式下，所以用户态进程是无法象 DOS 那样使用显卡 BIOS 里提供的中断调用来实现直接写屏，Linux 抽象出 FrameBuffer 这个设备来供用户态进程实现直接写屏。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220118092227.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220118092227.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;帧缓冲主要结构&#34;&gt;帧缓冲主要结构&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;fb_info
该结构体记录当前帧缓冲设备的状态信息，如果系统中有多个帧缓冲设备，就需要两个fb_info结构，这个结构只在内核中可以看到，对用户空间不可见。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fb_var_screeninfo
该结构体记录指定的帧缓冲设备和显示模式中可以被修改的信息，其中包括显示器分辨率等信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fb_fix_screeninfo
该结构体表示帧缓冲设备中一些不能修改的参数，包括特定的显示模式，屏幕缓冲区的物理地址，显示缓冲区的长度信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fb_ops
LCD底层硬件操作接口集。比如&lt;code&gt;fb_open&lt;/code&gt;、&lt;code&gt;fb_release&lt;/code&gt;、&lt;code&gt;fb_read&lt;/code&gt;、&lt;code&gt;fb_write&lt;/code&gt;、&lt;code&gt;fb_ioctl&lt;/code&gt;、&lt;code&gt;fb_mmap&lt;/code&gt;等：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fb_cmap
&lt;code&gt;fb_cmap&lt;/code&gt;指定颜色映射，用于以内核可以理解的方式存储用户的颜色定义。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220117192106.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220117192106.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;帧缓冲显示原理&#34;&gt;帧缓冲显示原理&lt;/h2&gt;
&lt;p&gt;帧缓冲设备是一种显示抽象的设备，也可以被理解为它是一个内存区域，上面的应用程序可以直接对显示缓冲区进行读和写操作，就像访问文件的通用接口一样，用户可以认为帧缓冲是一块内存，能读取数据的内存块也可以向这个内存写入数据，因此显示器显示图形界面实际上根据根据的是指定的内存数据块内的数据。&lt;/p&gt;
&lt;p&gt;帧缓冲的显示缓冲区位于 Linux 内核地址空间，应用程序不能直接访问内核地址空间，在 Linux 中，只有一个内存的内核地址空间映射到用户地址空间才可以由用户访问，内存的映射是通过&lt;code&gt;MMAP&lt;/code&gt;函数实现的在 Linux 中。对于帧缓冲，虚拟地址是通过内存映射的方法将显示缓冲区内核地址映射到用户空间的，然后用户可以通过读和写这部分的虚拟地址来访问显示缓冲区，在屏幕上绘图。&lt;/p&gt;
&lt;h2 id=&#34;使用流程&#34;&gt;使用流程&lt;/h2&gt;
&lt;p&gt;使用帧缓冲之前应该首先确定 Linux 系统上已安装了帧缓冲驱动，可以在目录&lt;code&gt;/dev/&lt;/code&gt;下查找&lt;code&gt;fb*&lt;/code&gt;如，&lt;code&gt;/dev/fb0, /dev/fb1&lt;/code&gt;等设备来确定是否安装。如果没有需要安装一个帧缓冲驱动的模块到内核，或者重新编译内核生成一个带帧缓冲模块的镜像。&lt;/p&gt;
&lt;p&gt;使用帧缓冲需要进入控制台模式，即纯命令行的模式进行编程。一般可以通过快捷键&lt;code&gt;CTRL+ALT+F1&lt;/code&gt;进入控制台模式，&lt;code&gt;CTRL+ALT+F7&lt;/code&gt;切回图形窗口。如果控制台模式没有登录，可以&lt;code&gt;CTRL+ALT+F6&lt;/code&gt;尝试登录。&lt;/p&gt;
&lt;p&gt;因硬件显示设备的物理显示区是通过帧缓存区操作，而帧缓存区是处于内核空间，应用程序不能随意操作，此时可以通过系统调用&lt;code&gt;mmap&lt;/code&gt;把帧缓存映射到用户空间，在用户空间中创建出帧缓存映射区（用户图像数据缓存区），以后只需把用户图像数据写入到帧缓存映射区就可在硬件设备上显示图像。&lt;/p&gt;
&lt;p&gt;具体实现流程如下：&lt;/p&gt;
&lt;h3 id=&#34;打开帧缓冲设备devf0&#34;&gt;打开帧缓冲设备&lt;code&gt;/dev/f0&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;在Linux的/dev目录的寻找b*设备文件然后使用读写模式打开它，Linux 系统将使用通用的&lt;code&gt;open&lt;/code&gt;系统调用来完成功能， &lt;code&gt;open&lt;/code&gt;的功能原型如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ne&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oflags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Path&lt;/code&gt;是准备打开的文件或设备的路径参数；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oflags&lt;/code&gt;指定打开文件时使用的参数；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flags&lt;/code&gt;参数的指定，是通过组合文件访问模式和其他的可选模式一起的，可以支持多个模式或，参数必须是指定下列文件的访问模式。
&lt;ul&gt;
&lt;li&gt;只读：O_RDONLLY&lt;/li&gt;
&lt;li&gt;只写：O_WRONLY&lt;/li&gt;
&lt;li&gt;读写：O_RDWR&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简而言之， &lt;code&gt;open&lt;/code&gt;函数建立设备文件的访问路径。如果操作成功，它返回一个文件描述符，只是一个文件描述符，它将不使用其他任何正在运行的进程共享。如果两个程序同时打开相同的文件，将得到两个不同的文件描述符。如果他们执行文件写入操作，他们将操作每个文件描述符，不会发生冲突，写完之后退出。他们的数据不会互相交织在一起的，但会互相的彼此覆盖 (后写完的内容覆盖前面写的内容)，两个程序来读取和写入的文件位置看似一样但是有各自不同拷贝所以不会发生交织。如果&lt;code&gt;open&lt;/code&gt;调用未能返回&lt;code&gt;1&lt;/code&gt;，则将全局变量&lt;code&gt;errno&lt;/code&gt;设置为指示失败的原因。&lt;/p&gt;
&lt;h3 id=&#34;通过系统调用ioctl函数获得帧设备相关信息&#34;&gt;通过系统调用&lt;code&gt;ioctl&lt;/code&gt;函数获得帧设备相关信息&lt;/h3&gt;
&lt;p&gt;通过顿缓冲文件描述符，屏幕的分辨率、颜色深度等信息可以被获得，帧缓冲驱动中存放了这些对应的信息，必须使用 Linux 系统调用&lt;code&gt;ioctl&lt;/code&gt;首先将帧缓冲的文件描述符和&lt;code&gt;fb_var_screeninfo&lt;/code&gt; 结构体对应起来。&lt;/p&gt;
&lt;p&gt;结构体&lt;code&gt;fb_var_screeninfo&lt;/code&gt;包含以下三个重要数据结构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;屏幕的 x 方向分辨率，像素作为单位。&lt;/li&gt;
&lt;li&gt;屏幕的 Y 方向分辨率，像素作为单位。&lt;/li&gt;
&lt;li&gt;屏幕的像素颜色深度，每个像素用多少比特数表示。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;ioctl&lt;/code&gt;函数原型如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ioctl&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__THROW&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ioctl&lt;/code&gt;调用实现访问设备驱动各种各样的配置信息功能，它提供了一个控制设备的行为和配置底层服务接口的驱动函数，各种设备驱动程序，例如套接字和系统终端，还有磁带机都有&lt;code&gt;ioctl&lt;/code&gt;命令可以支持。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;__fd&lt;/code&gt;：&lt;code&gt;ioctl&lt;/code&gt;命令中是该帧缓冲的文件描述符；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__request&lt;/code&gt;：&lt;code&gt;ioctl&lt;/code&gt;函数将要执行的命令，实现参数给定的对象描述符中指定的函数操作，各种设备支持的功能是有差异的
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FBIOGET_VSCREENINFO&lt;/code&gt;命令字返回与Framebuffer有关的固定的信息；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FBIOGET_VSCREENINFO&lt;/code&gt;命令字返回与 Framebuffer 有关的可变的信息；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;第三个参数是一个指针用来指向结构体&lt;code&gt;fb_var_screeninfo&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后使用者可以通过结构体&lt;code&gt;fb_var_screeninfo&lt;/code&gt;来获得屏幕的分辨率和颜色位深和其他重要的屏幕信息。根据这些信息可以计算屏幕缓冲区的大小：屏幕缓冲区大小 (以字节为单位) = 屏幕宽度x高度x屏幕颜色深度/8&lt;/p&gt;
&lt;h3 id=&#34;帧缓冲映射&#34;&gt;帧缓冲映射&lt;/h3&gt;
&lt;p&gt;在进行帧缓冲的&lt;code&gt;MMAP&lt;/code&gt;映射之前，要先得到帧缓冲文件描述符，才能像屏幕上面显示，必须首先将缓冲区的内核地址映射映射到用户地址空间。Linux 系统将使用&lt;code&gt;MMAP&lt;/code&gt;系统调用完成功能，&lt;code&gt;MMAP&lt;/code&gt;函数原型如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;mmap&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__prot&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__off_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__THROW&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;__addr&lt;/code&gt;：返回一个指向&lt;code&gt;mmap&lt;/code&gt;函数的内存区域的指针，与内容相关的文件指针，通过指针可以访问帧缓冲区的内存区域。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;__len&lt;/code&gt;：可以请求使用特定内存地址，通过设置地址参数，如果值为&lt;code&gt;0&lt;/code&gt;，将自动分配指针，这是推荐的做法，否则会降低程序的可移植性，因为不同的系统可用的地址范围是不一样的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;__prot&lt;/code&gt;：设置内存访问的权限设定，通过端口相关的参数定义，位的定义值如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PORT_EXEC&lt;/code&gt;:允许内存段的执行。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PORT_NONE&lt;/code&gt;:无法访问内存段。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PORT_READ&lt;/code&gt;:允许读取内存段。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PORT_WRITE&lt;/code&gt;:允许编写内存段。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;__flags&lt;/code&gt;：改变控制参数标志，能够影响该内存段的作用域，如下所示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MAP_FIXED&lt;/code&gt;:内存段必须位于addr中指定的地址。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MAP_SHARED&lt;/code&gt;:内存的修改保存到一个文件中。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MAP_PRIVATE&lt;/code&gt;:内存段是私人的，变化仅在本地范围内有效。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;__fd&lt;/code&gt;：是通过一个&lt;code&gt;open&lt;/code&gt;调用得到的访问文件的描述符。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;offset&lt;/code&gt;：用于指定访问数据的开始偏移量在内存段中，和访问普通文件使用方式是相同的，再指定文件描述符参数，以及访问的数据长度参数即可。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;读写帧缓冲&#34;&gt;读写帧缓冲&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;MMAP&lt;/code&gt;返回的指针，可以访问到帧缓冲内存区，可以定位到屏幕缓冲区具体为每个显示像素的位置，通过读函数调用读取对应的位置数据在帧缓冲内存中，相反写操作对应于内存的写入数据可以显示内容写到屏幕上。&lt;/p&gt;
&lt;h3 id=&#34;解除帧缓冲映射&#34;&gt;解除帧缓冲映射&lt;/h3&gt;
&lt;p&gt;在绘图完成后，帧缓冲文件描述符必须被释放之前，解除帧缓冲区的地址映射，使用 Linux 系统调用完成&lt;code&gt;mmap&lt;/code&gt;函数的逆函数实现，即是&lt;code&gt;munmap&lt;/code&gt;，函数的原型如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;munmap&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__THROW&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;addr&lt;/code&gt;参数应该与调用&lt;code&gt;MMAP&lt;/code&gt;时指定的参数值一致， &lt;code&gt;len&lt;/code&gt;参数也应该与之前调用&lt;code&gt;MMAP&lt;/code&gt;时指定的&lt;code&gt;len&lt;/code&gt;参数保持一致。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mmap&lt;/code&gt;调用返回&lt;code&gt;0&lt;/code&gt;成功，失败则返回&lt;code&gt;1&lt;/code&gt;，同时将全局变量&lt;code&gt;erno&lt;/code&gt;设置为指示失败的原因。&lt;/p&gt;
&lt;h3 id=&#34;调用close关闭设备&#34;&gt;调用&lt;code&gt;close&lt;/code&gt;关闭设备&lt;/h3&gt;
&lt;p&gt;使用帧缓冲设备后，应关闭相应的文件描述符，使用 Linux 系统标准的函数完成关闭功能，&lt;code&gt;close&lt;/code&gt;函数的原型如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;close&lt;/code&gt;的参数和在开始调用&lt;code&gt;open&lt;/code&gt;时指定的参数一致，文件描述符释放后可以重用，结束调用成功返回&lt;code&gt;0&lt;/code&gt;，失败返回&lt;code&gt;1&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;帧缓冲实例&#34;&gt;帧缓冲实例&lt;/h2&gt;
&lt;p&gt;以下代码摘自&lt;a href=&#34;https://github.com/xianjimli/linux-framebuffer-tools&#34;&gt;xianjimli/linux-framebuffer-tools: linux framebuffer tool&lt;/a&gt;，演示了帧缓冲设备的使用流程。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;fb_info_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;linux_fb_open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uint32_t&lt;/span&gt;                 &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;fb_info_t&lt;/span&gt;               &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fb_fix_screeninfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fb_var_screeninfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;return_value_if_fail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;fb_info_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;calloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;fb_info_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;return_value_if_fail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 打开帧缓冲设备，O_RDWR 读写模式
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;O_RDWR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;open %s failed(%d)&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 通过系统调用 ioctl 函数获得帧设备相关信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// FBIOGET_FSCREENINFO 命令字返回与 Framebuffer 有关的固定的信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FBIOGET_FSCREENINFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//命令字返回与 Framebuffer 有关的可变的信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FBIOGET_VSCREENINFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xoffset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;yoffset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 显示
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;ioctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FBIOPAN_DISPLAY&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;fb_info_t: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;fb_info_t: xres=%d yres=%d bits_per_pixel=%d mem_size=%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;yres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bits_per_pixel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fb_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;fb_info_t: red(%d %d) green(%d %d) blue(%d %d)&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;red&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;red&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;green&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;green&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;offset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;blue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;w&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;yres&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bpp&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bits_per_pixel&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line_length&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line_length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fb_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 帧缓冲映射
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// PROT_READ | PROT_WRITE:可读写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// MAP_SHARED：内存的修改保存到一个文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;mmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PROT_READ&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PROT_WRITE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAP_SHARED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAP_FAILED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;map framebuffer failed.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;line_length=%d mem_size=%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;line_length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fb_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;xres_virtual =%d yres_virtual=%d xpanstep=%d ywrapstep=%d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xres_virtual&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;yres_virtual&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xpanstep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ywrapstep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;fail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s is not a framebuffer.&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;感兴趣可以下载源码编译运行，其中&lt;code&gt;/bin/fbshow&lt;/code&gt;可以使用帧缓冲设备显示图片。图形界面下直接运行可能提示无法运行，需要&lt;code&gt;Chrtl+Alt+F1&lt;/code&gt;切换到控制台模式。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220120202118.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220120202118.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;lcd-与-framebuffer-的关系&#34;&gt;LCD 与 Framebuffer 的关系&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220225141549.jpg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220225141549.jpg&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;LCD 控制器首先通过 VDEN 信号，使能。接下来根据 VCLK 时钟信号，在像素点上“喷涂”不同的颜色（打个比方），控制器有 VD（video data）信号，传送不同颜色信息。每来一个时钟信号，就向右移动一个像素，根据行同步信号 HSYNC，就从最右边移动到最左边。当移动到右下角时根据垂直同步信号 VSYNC。&lt;/p&gt;
&lt;p&gt;那么问题来了，不同颜色的信息从哪里来？就是从上文介绍的 Framebuffer 中来的。&lt;/p&gt;
&lt;p&gt;很多人都会说操纵 LCD 显示就是操纵 FrameBuffer，表面上来看是这样的。实际上是 FrameBuffer 就是 Linux 内核驱动申请的一片内存空间，然后 LCD 内有一片 sram，CPU 内部有个 LCD 控制器，它有个单独的 dma 用来将 FrameBuffer 中的数据拷贝到 LCD 的 sram 中去 拷贝到 LCD 的 sram 中的数据就会显示在 LCD 上，LCD 驱动和 FrameBuffer 驱动没有必然的联系，它只是驱动 LCD 正常工作的，比如有信号传过来，那么 LCD 驱动负责把信号转成显示屏上的内容，至于什么内容这就是应用层要处理的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;静态随机存取存储器（Static Random-Access Memory，SRAM）是随机存取存储器的一种。所谓的“静态”，是指这种存储器只要保持通电，里面储存的数据就可以恒常保持。
DMA（Direct Memory Access），直接内存访问。使用 DMA 的好处就是它不需要 CPU 的干预而直接服务外设，这样 CPU 就可以去处理别的事务，从而提高系统的效率。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://carlyleliu.github.io/2021/Linux%E9%A9%B1%E5%8A%A8%E4%B9%8BFramebuffer%E5%AD%90%E7%B3%BB%E7%BB%9F/&#34;&gt;Linux 驱动之 Framebuffer 子系统 | 量子范式&lt;/a&gt;
&lt;a href=&#34;https://www.codenong.com/cs106598190/&#34;&gt;Linux 驱动开发（9）——- framebuffer 驱动详解 | 码农家园&lt;/a&gt;
&lt;a href=&#34;https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CMFD&amp;amp;dbname=CMFD201502&amp;amp;filename=1015587486.nh&amp;amp;uniplatform=NZKPT&amp;amp;v=KNvhApgKTzqH-mWxqP6f8BkbDR9mSjPHz8PfaxqDg2f1j30XqnHzSDsvwoqz-CbX&#34;&gt;嵌入式系统中帧缓冲显示模块的设计与实现 - 中国知网&lt;/a&gt;
&lt;a href=&#34;https://github.com/tsuibin/research/tree/master/framebuffer/fivechess/fivechess-0.1&#34;&gt;research/framebuffer/fivechess/fivechess-0.1 at master · tsuibin/research&lt;/a&gt;
&lt;a href=&#34;https://www.shangmayuan.com/a/f67d260756ce42258a9ed4ef.html&#34;&gt;五子棋 framebuffer 版 - 尚码园&lt;/a&gt;
&lt;a href=&#34;https://blog.csdn.net/yangwen123/article/details/12096483&#34;&gt;FrameBuffer 驱动程序分析_深入剖析 Android 系统-CSDN 博客_framebuffer&lt;/a&gt;
&lt;a href=&#34;https://github.com/xianjimli/linux-framebuffer-tools&#34;&gt;xianjimli/linux-framebuffer-tools: linux framebuffer tool&lt;/a&gt;
&lt;a href=&#34;https://www.bilibili.com/video/BV1HW411L76t?p=2&#34;&gt;韦东山_嵌入式 Linux_第 2 期_Linux 高级驱动视频教程_免费试看版_哔哩哔哩_bilibili&lt;/a&gt;
&lt;a href=&#34;https://zhuanlan.zhihu.com/p/356443723&#34;&gt;Linux LCD Frambuffer 基础介绍和使用（1） - 知乎&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="简介">简介</h2>
<p>FrameBuffer 是内核当中的一种驱动程序接口。Linux 是工作在保护模式下，所以用户态进程是无法象 DOS 那样使用显卡 BIOS 里提供的中断调用来实现直接写屏，Linux 抽象出 FrameBuffer 这个设备来供用户态进程实现直接写屏。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220118092227.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220118092227.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="帧缓冲主要结构">帧缓冲主要结构</h2>
<ul>
<li>
<p>fb_info
该结构体记录当前帧缓冲设备的状态信息，如果系统中有多个帧缓冲设备，就需要两个fb_info结构，这个结构只在内核中可以看到，对用户空间不可见。</p>
</li>
<li>
<p>fb_var_screeninfo
该结构体记录指定的帧缓冲设备和显示模式中可以被修改的信息，其中包括显示器分辨率等信息。</p>
</li>
<li>
<p>fb_fix_screeninfo
该结构体表示帧缓冲设备中一些不能修改的参数，包括特定的显示模式，屏幕缓冲区的物理地址，显示缓冲区的长度信息。</p>
</li>
<li>
<p>fb_ops
LCD底层硬件操作接口集。比如<code>fb_open</code>、<code>fb_release</code>、<code>fb_read</code>、<code>fb_write</code>、<code>fb_ioctl</code>、<code>fb_mmap</code>等：</p>
</li>
<li>
<p>fb_cmap
<code>fb_cmap</code>指定颜色映射，用于以内核可以理解的方式存储用户的颜色定义。</p>
</li>
</ul>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220117192106.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220117192106.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="帧缓冲显示原理">帧缓冲显示原理</h2>
<p>帧缓冲设备是一种显示抽象的设备，也可以被理解为它是一个内存区域，上面的应用程序可以直接对显示缓冲区进行读和写操作，就像访问文件的通用接口一样，用户可以认为帧缓冲是一块内存，能读取数据的内存块也可以向这个内存写入数据，因此显示器显示图形界面实际上根据根据的是指定的内存数据块内的数据。</p>
<p>帧缓冲的显示缓冲区位于 Linux 内核地址空间，应用程序不能直接访问内核地址空间，在 Linux 中，只有一个内存的内核地址空间映射到用户地址空间才可以由用户访问，内存的映射是通过<code>MMAP</code>函数实现的在 Linux 中。对于帧缓冲，虚拟地址是通过内存映射的方法将显示缓冲区内核地址映射到用户空间的，然后用户可以通过读和写这部分的虚拟地址来访问显示缓冲区，在屏幕上绘图。</p>
<h2 id="使用流程">使用流程</h2>
<p>使用帧缓冲之前应该首先确定 Linux 系统上已安装了帧缓冲驱动，可以在目录<code>/dev/</code>下查找<code>fb*</code>如，<code>/dev/fb0, /dev/fb1</code>等设备来确定是否安装。如果没有需要安装一个帧缓冲驱动的模块到内核，或者重新编译内核生成一个带帧缓冲模块的镜像。</p>
<p>使用帧缓冲需要进入控制台模式，即纯命令行的模式进行编程。一般可以通过快捷键<code>CTRL+ALT+F1</code>进入控制台模式，<code>CTRL+ALT+F7</code>切回图形窗口。如果控制台模式没有登录，可以<code>CTRL+ALT+F6</code>尝试登录。</p>
<p>因硬件显示设备的物理显示区是通过帧缓存区操作，而帧缓存区是处于内核空间，应用程序不能随意操作，此时可以通过系统调用<code>mmap</code>把帧缓存映射到用户空间，在用户空间中创建出帧缓存映射区（用户图像数据缓存区），以后只需把用户图像数据写入到帧缓存映射区就可在硬件设备上显示图像。</p>
<p>具体实现流程如下：</p>
<h3 id="打开帧缓冲设备devf0">打开帧缓冲设备<code>/dev/f0</code></h3>
<p>在Linux的/dev目录的寻找b*设备文件然后使用读写模式打开它，Linux 系统将使用通用的<code>open</code>系统调用来完成功能， <code>open</code>的功能原型如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="ne">int</span> <span class="n">open</span><span class="p">(</span><span class="k">const</span> <span class="n">char</span> <span class="o">*</span><span class="n">path</span><span class="p">,</span> <span class="ne">int</span> <span class="n">oflags</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li><code>Path</code>是准备打开的文件或设备的路径参数；</li>
<li><code>oflags</code>指定打开文件时使用的参数；</li>
<li><code>flags</code>参数的指定，是通过组合文件访问模式和其他的可选模式一起的，可以支持多个模式或，参数必须是指定下列文件的访问模式。
<ul>
<li>只读：O_RDONLLY</li>
<li>只写：O_WRONLY</li>
<li>读写：O_RDWR</li>
</ul>
</li>
</ul>
<p>简而言之， <code>open</code>函数建立设备文件的访问路径。如果操作成功，它返回一个文件描述符，只是一个文件描述符，它将不使用其他任何正在运行的进程共享。如果两个程序同时打开相同的文件，将得到两个不同的文件描述符。如果他们执行文件写入操作，他们将操作每个文件描述符，不会发生冲突，写完之后退出。他们的数据不会互相交织在一起的，但会互相的彼此覆盖 (后写完的内容覆盖前面写的内容)，两个程序来读取和写入的文件位置看似一样但是有各自不同拷贝所以不会发生交织。如果<code>open</code>调用未能返回<code>1</code>，则将全局变量<code>errno</code>设置为指示失败的原因。</p>
<h3 id="通过系统调用ioctl函数获得帧设备相关信息">通过系统调用<code>ioctl</code>函数获得帧设备相关信息</h3>
<p>通过顿缓冲文件描述符，屏幕的分辨率、颜色深度等信息可以被获得，帧缓冲驱动中存放了这些对应的信息，必须使用 Linux 系统调用<code>ioctl</code>首先将帧缓冲的文件描述符和<code>fb_var_screeninfo</code> 结构体对应起来。</p>
<p>结构体<code>fb_var_screeninfo</code>包含以下三个重要数据结构：</p>
<ul>
<li>屏幕的 x 方向分辨率，像素作为单位。</li>
<li>屏幕的 Y 方向分辨率，像素作为单位。</li>
<li>屏幕的像素颜色深度，每个像素用多少比特数表示。</li>
</ul>
<p><code>ioctl</code>函数原型如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">extern</span> <span class="kt">int</span> <span class="nf">ioctl</span> <span class="p">(</span><span class="kt">int</span> <span class="n">__fd</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">int</span> <span class="n">__request</span><span class="p">,</span> <span class="p">...)</span> <span class="n">__THROW</span><span class="p">;</span>
</span></span></code></pre></div><p><code>ioctl</code>调用实现访问设备驱动各种各样的配置信息功能，它提供了一个控制设备的行为和配置底层服务接口的驱动函数，各种设备驱动程序，例如套接字和系统终端，还有磁带机都有<code>ioctl</code>命令可以支持。</p>
<ul>
<li><code>__fd</code>：<code>ioctl</code>命令中是该帧缓冲的文件描述符；</li>
<li><code>__request</code>：<code>ioctl</code>函数将要执行的命令，实现参数给定的对象描述符中指定的函数操作，各种设备支持的功能是有差异的
<ul>
<li><code>FBIOGET_VSCREENINFO</code>命令字返回与Framebuffer有关的固定的信息；</li>
<li><code>FBIOGET_VSCREENINFO</code>命令字返回与 Framebuffer 有关的可变的信息；</li>
</ul>
</li>
<li>第三个参数是一个指针用来指向结构体<code>fb_var_screeninfo</code>。</li>
</ul>
<p>最后使用者可以通过结构体<code>fb_var_screeninfo</code>来获得屏幕的分辨率和颜色位深和其他重要的屏幕信息。根据这些信息可以计算屏幕缓冲区的大小：屏幕缓冲区大小 (以字节为单位) = 屏幕宽度x高度x屏幕颜色深度/8</p>
<h3 id="帧缓冲映射">帧缓冲映射</h3>
<p>在进行帧缓冲的<code>MMAP</code>映射之前，要先得到帧缓冲文件描述符，才能像屏幕上面显示，必须首先将缓冲区的内核地址映射映射到用户地址空间。Linux 系统将使用<code>MMAP</code>系统调用完成功能，<code>MMAP</code>函数原型如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">extern</span> <span class="kt">void</span> <span class="o">*</span><span class="nf">mmap</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">__addr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">__len</span><span class="p">,</span> <span class="kt">int</span> <span class="n">__prot</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">     <span class="kt">int</span> <span class="n">__flags</span><span class="p">,</span> <span class="kt">int</span> <span class="n">__fd</span><span class="p">,</span> <span class="n">__off_t</span> <span class="n">__offset</span><span class="p">)</span> <span class="n">__THROW</span><span class="p">;</span>
</span></span></code></pre></div><ul>
<li>
<p><code>__addr</code>：返回一个指向<code>mmap</code>函数的内存区域的指针，与内容相关的文件指针，通过指针可以访问帧缓冲区的内存区域。</p>
</li>
<li>
<p><code>__len</code>：可以请求使用特定内存地址，通过设置地址参数，如果值为<code>0</code>，将自动分配指针，这是推荐的做法，否则会降低程序的可移植性，因为不同的系统可用的地址范围是不一样的。</p>
</li>
<li>
<p><code>__prot</code>：设置内存访问的权限设定，通过端口相关的参数定义，位的定义值如下：</p>
<ul>
<li><code>PORT_EXEC</code>:允许内存段的执行。</li>
<li><code>PORT_NONE</code>:无法访问内存段。</li>
<li><code>PORT_READ</code>:允许读取内存段。</li>
<li><code>PORT_WRITE</code>:允许编写内存段。</li>
</ul>
</li>
<li>
<p><code>__flags</code>：改变控制参数标志，能够影响该内存段的作用域，如下所示：</p>
<ul>
<li><code>MAP_FIXED</code>:内存段必须位于addr中指定的地址。</li>
<li><code>MAP_SHARED</code>:内存的修改保存到一个文件中。</li>
<li><code>MAP_PRIVATE</code>:内存段是私人的，变化仅在本地范围内有效。</li>
</ul>
</li>
<li>
<p><code>__fd</code>：是通过一个<code>open</code>调用得到的访问文件的描述符。</p>
</li>
<li>
<p><code>offset</code>：用于指定访问数据的开始偏移量在内存段中，和访问普通文件使用方式是相同的，再指定文件描述符参数，以及访问的数据长度参数即可。</p>
</li>
</ul>
<h3 id="读写帧缓冲">读写帧缓冲</h3>
<p><code>MMAP</code>返回的指针，可以访问到帧缓冲内存区，可以定位到屏幕缓冲区具体为每个显示像素的位置，通过读函数调用读取对应的位置数据在帧缓冲内存中，相反写操作对应于内存的写入数据可以显示内容写到屏幕上。</p>
<h3 id="解除帧缓冲映射">解除帧缓冲映射</h3>
<p>在绘图完成后，帧缓冲文件描述符必须被释放之前，解除帧缓冲区的地址映射，使用 Linux 系统调用完成<code>mmap</code>函数的逆函数实现，即是<code>munmap</code>，函数的原型如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">extern</span> <span class="kt">int</span> <span class="nf">munmap</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">__addr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">__len</span><span class="p">)</span> <span class="n">__THROW</span><span class="p">;</span>
</span></span></code></pre></div><p><code>addr</code>参数应该与调用<code>MMAP</code>时指定的参数值一致， <code>len</code>参数也应该与之前调用<code>MMAP</code>时指定的<code>len</code>参数保持一致。</p>
<p><code>mmap</code>调用返回<code>0</code>成功，失败则返回<code>1</code>，同时将全局变量<code>erno</code>设置为指示失败的原因。</p>
<h3 id="调用close关闭设备">调用<code>close</code>关闭设备</h3>
<p>使用帧缓冲设备后，应关闭相应的文件描述符，使用 Linux 系统标准的函数完成关闭功能，<code>close</code>函数的原型如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">extern</span> <span class="kt">int</span> <span class="nf">close</span> <span class="p">(</span><span class="kt">int</span> <span class="n">__fd</span><span class="p">);</span>
</span></span></code></pre></div><p><code>close</code>的参数和在开始调用<code>open</code>时指定的参数一致，文件描述符释放后可以重用，结束调用成功返回<code>0</code>，失败返回<code>1</code>。</p>
<h2 id="帧缓冲实例">帧缓冲实例</h2>
<p>以下代码摘自<a href="https://github.com/xianjimli/linux-framebuffer-tools">xianjimli/linux-framebuffer-tools: linux framebuffer tool</a>，演示了帧缓冲设备的使用流程。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">fb_info_t</span> <span class="o">*</span><span class="nf">linux_fb_open</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">filename</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uint32_t</span>                 <span class="n">size</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">fb_info_t</span>               <span class="o">*</span><span class="n">fb</span>   <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">fb_fix_screeninfo</span> <span class="n">fix</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">fb_var_screeninfo</span> <span class="n">var</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">return_value_if_fail</span><span class="p">(</span><span class="n">filename</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fb</span> <span class="o">=</span> <span class="p">(</span><span class="kt">fb_info_t</span> <span class="o">*</span><span class="p">)</span><span class="nf">calloc</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="kt">fb_info_t</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nf">return_value_if_fail</span><span class="p">(</span><span class="n">fb</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 打开帧缓冲设备，O_RDWR 读写模式
</span></span></span><span class="line"><span class="cl">    <span class="n">fb</span><span class="o">-&gt;</span><span class="n">fd</span> <span class="o">=</span> <span class="nf">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">O_RDWR</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">fd</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">log_debug</span><span class="p">(</span><span class="s">&#34;open %s failed(%d)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">errno</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">free</span><span class="p">(</span><span class="n">fb</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 通过系统调用 ioctl 函数获得帧设备相关信息
</span></span></span><span class="line"><span class="cl">    <span class="c1">// FBIOGET_FSCREENINFO 命令字返回与 Framebuffer 有关的固定的信息
</span></span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">ioctl</span><span class="p">(</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">fd</span><span class="p">,</span> <span class="n">FBIOGET_FSCREENINFO</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fix</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">goto</span> <span class="n">fail</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//命令字返回与 Framebuffer 有关的可变的信息
</span></span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">ioctl</span><span class="p">(</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">fd</span><span class="p">,</span> <span class="n">FBIOGET_VSCREENINFO</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">var</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">goto</span> <span class="n">fail</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">var</span><span class="p">.</span><span class="n">xoffset</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">var</span><span class="p">.</span><span class="n">yoffset</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 显示
</span></span></span><span class="line"><span class="cl">    <span class="nf">ioctl</span><span class="p">(</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">fd</span><span class="p">,</span> <span class="n">FBIOPAN_DISPLAY</span><span class="p">,</span> <span class="o">&amp;</span><span class="p">(</span><span class="n">var</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">log_debug</span><span class="p">(</span><span class="s">&#34;fb_info_t: %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">filename</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">log_debug</span><span class="p">(</span><span class="s">&#34;fb_info_t: xres=%d yres=%d bits_per_pixel=%d mem_size=%d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">xres</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">yres</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="n">var</span><span class="p">.</span><span class="n">bits_per_pixel</span><span class="p">,</span> <span class="nf">fb_size</span><span class="p">(</span><span class="n">fb</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nf">log_debug</span><span class="p">(</span><span class="s">&#34;fb_info_t: red(%d %d) green(%d %d) blue(%d %d)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">red</span><span class="p">.</span><span class="n">offset</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">red</span><span class="p">.</span><span class="n">length</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="n">var</span><span class="p">.</span><span class="n">green</span><span class="p">.</span><span class="n">offset</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">green</span><span class="p">.</span><span class="n">length</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">blue</span><span class="p">.</span><span class="n">offset</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">blue</span><span class="p">.</span><span class="n">length</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">fb</span><span class="o">-&gt;</span><span class="n">w</span>           <span class="o">=</span> <span class="n">var</span><span class="p">.</span><span class="n">xres</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">fb</span><span class="o">-&gt;</span><span class="n">h</span>           <span class="o">=</span> <span class="n">var</span><span class="p">.</span><span class="n">yres</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">fb</span><span class="o">-&gt;</span><span class="n">bpp</span>         <span class="o">=</span> <span class="n">var</span><span class="p">.</span><span class="n">bits_per_pixel</span> <span class="o">/</span> <span class="mi">8</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">fb</span><span class="o">-&gt;</span><span class="n">line_length</span> <span class="o">=</span> <span class="n">fix</span><span class="p">.</span><span class="n">line_length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">size</span> <span class="o">=</span> <span class="nf">fb_size</span><span class="p">(</span><span class="n">fb</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 帧缓冲映射
</span></span></span><span class="line"><span class="cl">    <span class="c1">// PROT_READ | PROT_WRITE:可读写
</span></span></span><span class="line"><span class="cl">    <span class="c1">// MAP_SHARED：内存的修改保存到一个文件
</span></span></span><span class="line"><span class="cl">    <span class="n">fb</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="p">(</span><span class="kt">uint8_t</span> <span class="o">*</span><span class="p">)</span><span class="nf">mmap</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">PROT_READ</span> <span class="o">|</span> <span class="n">PROT_WRITE</span><span class="p">,</span> <span class="n">MAP_SHARED</span><span class="p">,</span> <span class="n">fb</span><span class="o">-&gt;</span><span class="n">fd</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">==</span> <span class="n">MAP_FAILED</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">log_debug</span><span class="p">(</span><span class="s">&#34;map framebuffer failed.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">goto</span> <span class="n">fail</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">log_debug</span><span class="p">(</span><span class="s">&#34;line_length=%d mem_size=%d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">fix</span><span class="p">.</span><span class="n">line_length</span><span class="p">,</span> <span class="nf">fb_size</span><span class="p">(</span><span class="n">fb</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="nf">log_debug</span><span class="p">(</span><span class="s">&#34;xres_virtual =%d yres_virtual=%d xpanstep=%d ywrapstep=%d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">xres_virtual</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="n">var</span><span class="p">.</span><span class="n">yres_virtual</span><span class="p">,</span> <span class="n">fix</span><span class="p">.</span><span class="n">xpanstep</span><span class="p">,</span> <span class="n">fix</span><span class="p">.</span><span class="n">ywrapstep</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">fb</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nl">fail</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nf">log_debug</span><span class="p">(</span><span class="s">&#34;%s is not a framebuffer.</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">filename</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">close</span><span class="p">(</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">fd</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">free</span><span class="p">(</span><span class="n">fb</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>感兴趣可以下载源码编译运行，其中<code>/bin/fbshow</code>可以使用帧缓冲设备显示图片。图形界面下直接运行可能提示无法运行，需要<code>Chrtl+Alt+F1</code>切换到控制台模式。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220120202118.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220120202118.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="lcd-与-framebuffer-的关系">LCD 与 Framebuffer 的关系</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220225141549.jpg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220225141549.jpg" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>LCD 控制器首先通过 VDEN 信号，使能。接下来根据 VCLK 时钟信号，在像素点上“喷涂”不同的颜色（打个比方），控制器有 VD（video data）信号，传送不同颜色信息。每来一个时钟信号，就向右移动一个像素，根据行同步信号 HSYNC，就从最右边移动到最左边。当移动到右下角时根据垂直同步信号 VSYNC。</p>
<p>那么问题来了，不同颜色的信息从哪里来？就是从上文介绍的 Framebuffer 中来的。</p>
<p>很多人都会说操纵 LCD 显示就是操纵 FrameBuffer，表面上来看是这样的。实际上是 FrameBuffer 就是 Linux 内核驱动申请的一片内存空间，然后 LCD 内有一片 sram，CPU 内部有个 LCD 控制器，它有个单独的 dma 用来将 FrameBuffer 中的数据拷贝到 LCD 的 sram 中去 拷贝到 LCD 的 sram 中的数据就会显示在 LCD 上，LCD 驱动和 FrameBuffer 驱动没有必然的联系，它只是驱动 LCD 正常工作的，比如有信号传过来，那么 LCD 驱动负责把信号转成显示屏上的内容，至于什么内容这就是应用层要处理的。</p>
<blockquote>
<p>静态随机存取存储器（Static Random-Access Memory，SRAM）是随机存取存储器的一种。所谓的“静态”，是指这种存储器只要保持通电，里面储存的数据就可以恒常保持。
DMA（Direct Memory Access），直接内存访问。使用 DMA 的好处就是它不需要 CPU 的干预而直接服务外设，这样 CPU 就可以去处理别的事务，从而提高系统的效率。</p>
</blockquote>
<h2 id="reference">Reference</h2>
<p><a href="https://carlyleliu.github.io/2021/Linux%E9%A9%B1%E5%8A%A8%E4%B9%8BFramebuffer%E5%AD%90%E7%B3%BB%E7%BB%9F/">Linux 驱动之 Framebuffer 子系统 | 量子范式</a>
<a href="https://www.codenong.com/cs106598190/">Linux 驱动开发（9）——- framebuffer 驱动详解 | 码农家园</a>
<a href="https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CMFD&amp;dbname=CMFD201502&amp;filename=1015587486.nh&amp;uniplatform=NZKPT&amp;v=KNvhApgKTzqH-mWxqP6f8BkbDR9mSjPHz8PfaxqDg2f1j30XqnHzSDsvwoqz-CbX">嵌入式系统中帧缓冲显示模块的设计与实现 - 中国知网</a>
<a href="https://github.com/tsuibin/research/tree/master/framebuffer/fivechess/fivechess-0.1">research/framebuffer/fivechess/fivechess-0.1 at master · tsuibin/research</a>
<a href="https://www.shangmayuan.com/a/f67d260756ce42258a9ed4ef.html">五子棋 framebuffer 版 - 尚码园</a>
<a href="https://blog.csdn.net/yangwen123/article/details/12096483">FrameBuffer 驱动程序分析_深入剖析 Android 系统-CSDN 博客_framebuffer</a>
<a href="https://github.com/xianjimli/linux-framebuffer-tools">xianjimli/linux-framebuffer-tools: linux framebuffer tool</a>
<a href="https://www.bilibili.com/video/BV1HW411L76t?p=2">韦东山_嵌入式 Linux_第 2 期_Linux 高级驱动视频教程_免费试看版_哔哩哔哩_bilibili</a>
<a href="https://zhuanlan.zhihu.com/p/356443723">Linux LCD Frambuffer 基础介绍和使用（1） - 知乎</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 安装 Node.js 以及 hexo</title>
      <link>https://lifeislife.cn/posts/linux%E5%AE%89%E8%A3%85nodejs/</link>
      <pubDate>Mon, 10 Jan 2022 11:51:50 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E5%AE%89%E8%A3%85nodejs/</guid>
      <description>&lt;h2 id=&#34;安装-nodejs-过程&#34;&gt;安装 Node.js 过程&lt;/h2&gt;
&lt;p&gt;进入该网站&lt;a href=&#34;https://nodejs.org/zh-cn/download/&#34;&gt;下载 | Node.js&lt;/a&gt;
也可以进入该网站下载历史版本，&lt;a href=&#34;https://nodejs.org/en/download/releases/&#34;&gt;Previous Releases | Node.js&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;进入 download 目录，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;download&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;wget&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodejs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dist&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v10&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;16.3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v10&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;16.3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linux&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xz&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;O&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodejs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解压&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar -xvf node-v10.16.3-linux-x64.tar.xz
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;改名 Node.js&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv node-v10.16.3-linux-x64 nodejs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 npm，node 两个程序建立软连接，能够全局可用&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ln&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;download&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodejs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;npm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ln&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;download&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodejs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查是否安装&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;node -v
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm -v
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;安装-hexo-过程&#34;&gt;安装 hexo 过程&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;npm i hexo-cli -g
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hexo -v
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果出现命令未找到到错误，说明 hexo 还未加入全局变量。
将下面命令加入&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;vim&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;~/.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bashrc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;local&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nodejs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;node_modules&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hexo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cli&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;$&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PATH&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://nodejs.org/en/download/releases/&#34;&gt;Previous Releases | Node.js&lt;/a&gt;
&lt;a href=&#34;https://learnku.com/articles/32767&#34;&gt;Linux 安装 Node.js | F2E 前端技术论坛&lt;/a&gt;
&lt;a href=&#34;https://segmentfault.com/a/1190000024422534&#34;&gt;Linux 下安装 node 及 npm - SegmentFault 思否&lt;/a&gt;
&lt;a href=&#34;https://zhuanlan.zhihu.com/p/35668237&#34;&gt;超详细 Hexo+Github 博客搭建小白教程 - 知乎&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="安装-nodejs-过程">安装 Node.js 过程</h2>
<p>进入该网站<a href="https://nodejs.org/zh-cn/download/">下载 | Node.js</a>
也可以进入该网站下载历史版本，<a href="https://nodejs.org/en/download/releases/">Previous Releases | Node.js</a></p>
<p>进入 download 目录，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">cd</span> <span class="n">download</span>
</span></span><span class="line"><span class="cl"><span class="n">wget</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">nodejs</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">dist</span><span class="o">/</span><span class="n">v10</span><span class="o">.</span><span class="mf">16.3</span><span class="o">/</span><span class="n">node</span><span class="o">-</span><span class="n">v10</span><span class="o">.</span><span class="mf">16.3</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">x64</span><span class="o">.</span><span class="n">tar</span><span class="o">.</span><span class="n">xz</span>  <span class="o">-</span><span class="n">O</span> <span class="n">nodejs</span><span class="o">.</span><span class="n">tar</span><span class="o">.</span><span class="n">xz</span>
</span></span></code></pre></div><p>解压</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">tar -xvf node-v10.16.3-linux-x64.tar.xz
</span></span></code></pre></div><p>改名 Node.js</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">mv node-v10.16.3-linux-x64 nodejs
</span></span></code></pre></div><p>将 npm，node 两个程序建立软连接，能够全局可用</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">ln</span> <span class="o">-</span><span class="n">s</span> <span class="o">/</span><span class="n">download</span><span class="o">/</span><span class="n">nodejs</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">npm</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span> 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">ln</span> <span class="o">-</span><span class="n">s</span> <span class="o">/</span><span class="n">download</span><span class="o">/</span><span class="n">nodejs</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">node</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span>
</span></span></code></pre></div><p>检查是否安装</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">node -v
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">npm -v
</span></span></code></pre></div><h2 id="安装-hexo-过程">安装 hexo 过程</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">npm i hexo-cli -g
</span></span><span class="line"><span class="cl">hexo -v
</span></span></code></pre></div><p>如果出现命令未找到到错误，说明 hexo 还未加入全局变量。
将下面命令加入</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">vim</span> <span class="o">~/.</span><span class="n">bashrc</span>
</span></span><span class="line"><span class="cl"><span class="k">export</span> <span class="n">PATH</span><span class="o">=/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">nodejs</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">node_modules</span><span class="o">/</span><span class="n">hexo</span><span class="o">-</span><span class="n">cli</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="p">:</span><span class="o">$</span><span class="n">PATH</span> 
</span></span></code></pre></div><h2 id="reference">Reference</h2>
<p><a href="https://nodejs.org/en/download/releases/">Previous Releases | Node.js</a>
<a href="https://learnku.com/articles/32767">Linux 安装 Node.js | F2E 前端技术论坛</a>
<a href="https://segmentfault.com/a/1190000024422534">Linux 下安装 node 及 npm - SegmentFault 思否</a>
<a href="https://zhuanlan.zhihu.com/p/35668237">超详细 Hexo+Github 博客搭建小白教程 - 知乎</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>解决 unable to install libpng12.so.0</title>
      <link>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3unable-to-install-libpng12-so-0/</link>
      <pubDate>Wed, 05 Jan 2022 13:01:47 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3unable-to-install-libpng12-so-0/</guid>
      <description>&lt;h2 id=&#34;保留现场&#34;&gt;保留现场&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;apt&lt;/code&gt;工具损坏了，在修复时使用了&lt;code&gt;sudo apt-get install -f&lt;/code&gt;命令，中途会提示需要安装&lt;code&gt;libpng12-0&lt;/code&gt;，但是始终无法安装，会提示如下错误。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Unpacking libpng12-0:amd64 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;1.2.50-2+deb8u3&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; ... dpkg: error 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;processing archive libpng12-0_1.2.50-2+deb8u3_amd64.deb 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;--install&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: unable to install new version of &lt;span class=&#34;s1&#34;&gt;&amp;#39;/usr/lib/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;x86_64-linux-gnu/libpng12.so.0&amp;#39;&lt;/span&gt;: No such file or directory 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Errors were encountered &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; processing: libpng12-0_1.2.50-2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+deb8u3_amd64.deb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;探究原因&#34;&gt;探究原因&lt;/h2&gt;
&lt;p&gt;具体原因未知，网上答案众说纷纭。&lt;/p&gt;
&lt;h2 id=&#34;解决方法&#34;&gt;解决方法&lt;/h2&gt;
&lt;p&gt;这个问题遇到的人还挺多的，解决方法也各不相同，我先说我自己最终解决的方法。&lt;/p&gt;
&lt;h3 id=&#34;方法一&#34;&gt;方法一&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;将软件源更换成中科院的源，使用 Linux 自带的&lt;strong&gt;软件和更新&lt;/strong&gt;工具，具体方法参考&lt;a href=&#34;https://dunky-z.github.io/2021/07/30/%E6%9B%B4%E6%8D%A2Ubuntu%E8%BD%AF%E4%BB%B6%E6%9B%B4%E6%96%B0%E6%BA%90/&#34;&gt;这篇文章&lt;/a&gt;。更换完之后可以重新尝试安装，有人换源后即可成功安装。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果未能安装成功，可能曾经手动添加过软件源，将其删除。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 将所有内容注释
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;方法二&#34;&gt;方法二&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;下载已安装的库文件&lt;code&gt;libpng12.so.0&lt;/code&gt;，可以从&lt;a href=&#34;https://www.aliyundrive.com/s/pf9cAPjuqfn&#34;&gt;该链接&lt;/a&gt;下载。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将该文件复制到它本该安装的位置。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo cp libpng12.so.0 /usr/lib/x86_64-linux-gnu/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;方法三&#34;&gt;方法三&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo add-apt-repository ppa:linuxuprising/libpng12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install libpng12-0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="保留现场">保留现场</h2>
<p><code>apt</code>工具损坏了，在修复时使用了<code>sudo apt-get install -f</code>命令，中途会提示需要安装<code>libpng12-0</code>，但是始终无法安装，会提示如下错误。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Unpacking libpng12-0:amd64 <span class="o">(</span>1.2.50-2+deb8u3<span class="o">)</span> ... dpkg: error 
</span></span><span class="line"><span class="cl">processing archive libpng12-0_1.2.50-2+deb8u3_amd64.deb 
</span></span><span class="line"><span class="cl"><span class="o">(</span>--install<span class="o">)</span>: unable to install new version of <span class="s1">&#39;/usr/lib/
</span></span></span><span class="line"><span class="cl"><span class="s1">x86_64-linux-gnu/libpng12.so.0&#39;</span>: No such file or directory 
</span></span><span class="line"><span class="cl">Errors were encountered <span class="k">while</span> processing: libpng12-0_1.2.50-2
</span></span><span class="line"><span class="cl">+deb8u3_amd64.deb
</span></span></code></pre></div><h2 id="探究原因">探究原因</h2>
<p>具体原因未知，网上答案众说纷纭。</p>
<h2 id="解决方法">解决方法</h2>
<p>这个问题遇到的人还挺多的，解决方法也各不相同，我先说我自己最终解决的方法。</p>
<h3 id="方法一">方法一</h3>
<ol>
<li>
<p>将软件源更换成中科院的源，使用 Linux 自带的<strong>软件和更新</strong>工具，具体方法参考<a href="https://dunky-z.github.io/2021/07/30/%E6%9B%B4%E6%8D%A2Ubuntu%E8%BD%AF%E4%BB%B6%E6%9B%B4%E6%96%B0%E6%BA%90/">这篇文章</a>。更换完之后可以重新尝试安装，有人换源后即可成功安装。</p>
</li>
<li>
<p>如果未能安装成功，可能曾经手动添加过软件源，将其删除。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 将所有内容注释
</span></span><span class="line"><span class="cl">vim /etc/apt/sources.list
</span></span></code></pre></div></li>
</ol>
<h3 id="方法二">方法二</h3>
<ol>
<li>
<p>下载已安装的库文件<code>libpng12.so.0</code>，可以从<a href="https://www.aliyundrive.com/s/pf9cAPjuqfn">该链接</a>下载。</p>
</li>
<li>
<p>将该文件复制到它本该安装的位置。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo cp libpng12.so.0 /usr/lib/x86_64-linux-gnu/
</span></span></code></pre></div></li>
</ol>
<h3 id="方法三">方法三</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo add-apt-repository ppa:linuxuprising/libpng12
</span></span><span class="line"><span class="cl">sudo apt update
</span></span><span class="line"><span class="cl">sudo apt install libpng12-0
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>VSCode 使用 sftp 插件上传本地文件至局域网服务器</title>
      <link>https://lifeislife.cn/posts/vscode%E4%BD%BF%E7%94%A8sftp%E6%8F%92%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6%E8%87%B3%E5%B1%80%E5%9F%9F%E7%BD%91%E6%9C%8D%E5%8A%A1%E5%99%A8/</link>
      <pubDate>Fri, 24 Dec 2021 11:39:03 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/vscode%E4%BD%BF%E7%94%A8sftp%E6%8F%92%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%9C%AC%E5%9C%B0%E6%96%87%E4%BB%B6%E8%87%B3%E5%B1%80%E5%9F%9F%E7%BD%91%E6%9C%8D%E5%8A%A1%E5%99%A8/</guid>
      <description>&lt;p&gt;测试代码时经常需要上传文件至服务器端运行，每次上传都需要通过第三方传输工具如 FileZilla，有了&lt;code&gt;SFTP&lt;/code&gt;插件，可以直接在 VSCode 上编译成功后，一键上传本地文件。&lt;/p&gt;
&lt;h2 id=&#34;安装插件&#34;&gt;安装插件&lt;/h2&gt;
&lt;p&gt;打开插件中心，搜索&lt;code&gt;sftp&lt;/code&gt;，安装量最高的就是我们需要的插件，点击安装。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104114810.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104114810.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;配置插件&#34;&gt;配置插件&lt;/h2&gt;
&lt;p&gt;插件安装完成后，输入快捷键&lt;code&gt;Control + Shift + P&lt;/code&gt; 弹出命令面板，然后输入&lt;code&gt;sftp:config&lt;/code&gt;，回车，当前工程的&lt;code&gt;.vscode&lt;/code&gt;文件夹下就会自动生成一个&lt;code&gt;sftp.json&lt;/code&gt;文件，我们需要在这个文件里配置的内容可以是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.xxx.xxx&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//服务器 ip
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;               &lt;span class=&#34;c1&#34;&gt;//端口，sftp 模式是 22
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;//用户名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;//密码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;ftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;//模式，sfpt 或者 ftp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;agent&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;privateKeyPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;//存放在本地的已配置好的用于登录工作站的密钥文件（也可以是 ppk 文件）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;passphrase&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;passive&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;interactiveAuth&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;remotePath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/root/node/build/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//服务器上的文件地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;context&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;./server/build&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;//本地的文件地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;uploadOnSave&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;             &lt;span class=&#34;c1&#34;&gt;//监听保存并上传
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;syncMode&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;update&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;watcher&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//监听外部文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;files&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;                 &lt;span class=&#34;c1&#34;&gt;//外部文件的绝对路径
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;autoUpload&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;autoDelete&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignore&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//指定在使用 sftp: sync to remote 的时候忽略的文件及文件夹
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//注意每一行后面有逗号，最后一行没有逗号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//忽略项
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/.vscode/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/.git/**&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;**/.DS_Store&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;插件使用&#34;&gt;插件使用&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可以直接右击文件，选择&lt;code&gt;Upload&lt;/code&gt;，会将文件上传至配置好的&lt;code&gt;remotePath&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以&lt;code&gt;Control + Shift + P&lt;/code&gt;输入&lt;code&gt;sftp&lt;/code&gt;，选择想要执行的命令，命令都是字面意思，不多做解释。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104115716.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104115716.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果有多个 IP 需要配置，可以在&lt;code&gt;sftp.json&lt;/code&gt;文件中，通过方括号&lt;code&gt;[]&lt;/code&gt;添加。比如&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.xxx.01&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//服务器 ip
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;               &lt;span class=&#34;c1&#34;&gt;//端口，sftp模式是22
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;//用户名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;//密码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;//模式，sfpt 或者 ftp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;agent&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.xxx.02&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//服务器 ip
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;               &lt;span class=&#34;c1&#34;&gt;//端口，sftp模式是22
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;//用户名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;//密码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;//模式，sfpt 或者 ftp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;agent&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;192.168.xxx.03&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//服务器 ip
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;22&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;               &lt;span class=&#34;c1&#34;&gt;//端口，sftp模式是22
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;//用户名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;           &lt;span class=&#34;c1&#34;&gt;//密码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sftp&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;//模式，sfpt 或者 ftp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;agent&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<p>测试代码时经常需要上传文件至服务器端运行，每次上传都需要通过第三方传输工具如 FileZilla，有了<code>SFTP</code>插件，可以直接在 VSCode 上编译成功后，一键上传本地文件。</p>
<h2 id="安装插件">安装插件</h2>
<p>打开插件中心，搜索<code>sftp</code>，安装量最高的就是我们需要的插件，点击安装。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104114810.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104114810.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="配置插件">配置插件</h2>
<p>插件安装完成后，输入快捷键<code>Control + Shift + P</code> 弹出命令面板，然后输入<code>sftp:config</code>，回车，当前工程的<code>.vscode</code>文件夹下就会自动生成一个<code>sftp.json</code>文件，我们需要在这个文件里配置的内容可以是：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.xxx.xxx&#34;</span><span class="p">,</span> <span class="c1">//服务器 ip
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>               <span class="c1">//端口，sftp 模式是 22
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>           <span class="c1">//用户名
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>           <span class="c1">//密码
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;ftp&#34;</span><span class="p">,</span>       <span class="c1">//模式，sfpt 或者 ftp
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;agent&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;privateKeyPath&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>   <span class="c1">//存放在本地的已配置好的用于登录工作站的密钥文件（也可以是 ppk 文件）
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;passphrase&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;passive&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;interactiveAuth&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;remotePath&#34;</span><span class="p">:</span> <span class="s2">&#34;/root/node/build/&#34;</span><span class="p">,</span> <span class="c1">//服务器上的文件地址
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;context&#34;</span><span class="p">:</span> <span class="s2">&#34;./server/build&#34;</span><span class="p">,</span>      <span class="c1">//本地的文件地址
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;uploadOnSave&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>             <span class="c1">//监听保存并上传
</span></span></span><span class="line"><span class="cl">  <span class="nt">&#34;syncMode&#34;</span><span class="p">:</span> <span class="s2">&#34;update&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;watcher&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//监听外部文件
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;files&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>                 <span class="c1">//外部文件的绝对路径
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;autoUpload&#34;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;autoDelete&#34;</span><span class="p">:</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;ignore&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="c1">//指定在使用 sftp: sync to remote 的时候忽略的文件及文件夹
</span></span></span><span class="line"><span class="cl">    <span class="c1">//注意每一行后面有逗号，最后一行没有逗号
</span></span></span><span class="line"><span class="cl">    <span class="c1">//忽略项
</span></span></span><span class="line"><span class="cl">    <span class="s2">&#34;**/.vscode/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;**/.git/**&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;**/.DS_Store&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="插件使用">插件使用</h2>
<ul>
<li>
<p>可以直接右击文件，选择<code>Upload</code>，会将文件上传至配置好的<code>remotePath</code>。</p>
</li>
<li>
<p>可以<code>Control + Shift + P</code>输入<code>sftp</code>，选择想要执行的命令，命令都是字面意思，不多做解释。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104115716.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220104115716.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
</li>
<li>
<p>如果有多个 IP 需要配置，可以在<code>sftp.json</code>文件中，通过方括号<code>[]</code>添加。比如</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.xxx.01&#34;</span><span class="p">,</span> <span class="c1">//服务器 ip
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>               <span class="c1">//端口，sftp模式是22
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>           <span class="c1">//用户名
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>           <span class="c1">//密码
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;sftp&#34;</span><span class="p">,</span>       <span class="c1">//模式，sfpt 或者 ftp
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;agent&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.xxx.02&#34;</span><span class="p">,</span> <span class="c1">//服务器 ip
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>               <span class="c1">//端口，sftp模式是22
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>           <span class="c1">//用户名
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>           <span class="c1">//密码
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;sftp&#34;</span><span class="p">,</span>       <span class="c1">//模式，sfpt 或者 ftp
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;agent&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;192.168.xxx.03&#34;</span><span class="p">,</span> <span class="c1">//服务器 ip
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">22</span><span class="p">,</span>               <span class="c1">//端口，sftp模式是22
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>           <span class="c1">//用户名
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>           <span class="c1">//密码
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;protocol&#34;</span><span class="p">:</span> <span class="s2">&#34;sftp&#34;</span><span class="p">,</span>       <span class="c1">//模式，sfpt 或者 ftp
</span></span></span><span class="line"><span class="cl">    <span class="nt">&#34;agent&#34;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></div></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>解决 Linux 启动出现 fsck exited with status code 4</title>
      <link>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3linux%E5%90%AF%E5%8A%A8%E5%87%BA%E7%8E%B0fsck-exited-with-status-code-4/</link>
      <pubDate>Sat, 04 Dec 2021 10:18:09 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3linux%E5%90%AF%E5%8A%A8%E5%87%BA%E7%8E%B0fsck-exited-with-status-code-4/</guid>
      <description>&lt;h2 id=&#34;保留现场&#34;&gt;保留现场&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112041102634.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112041102634.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;探究原因&#34;&gt;探究原因&lt;/h2&gt;
&lt;p&gt;磁盘检测不能通过，可能是因为系统突然断电或其它未正常关闭系统导致。&lt;/p&gt;
&lt;h2 id=&#34;解决方法&#34;&gt;解决方法&lt;/h2&gt;
&lt;p&gt;根据提示可以看到是&lt;code&gt;dev/sda5&lt;/code&gt;这个扇区出现了异常，所以通过&lt;code&gt;fsck&lt;/code&gt;命令修复文件系统。&lt;a href=&#34;https://www.runoob.com/linux/linux-comm-fsck.html&#34;&gt;详细命令解释&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;将&lt;code&gt;sda5&lt;/code&gt;改为自己损坏的扇区即可，等待一段时间修复完成后，输入&lt;code&gt;exit&lt;/code&gt;即可重启。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;fsck -y  /dev/sda5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="保留现场">保留现场</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112041102634.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112041102634.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="探究原因">探究原因</h2>
<p>磁盘检测不能通过，可能是因为系统突然断电或其它未正常关闭系统导致。</p>
<h2 id="解决方法">解决方法</h2>
<p>根据提示可以看到是<code>dev/sda5</code>这个扇区出现了异常，所以通过<code>fsck</code>命令修复文件系统。<a href="https://www.runoob.com/linux/linux-comm-fsck.html">详细命令解释</a>。</p>
<p>将<code>sda5</code>改为自己损坏的扇区即可，等待一段时间修复完成后，输入<code>exit</code>即可重启。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">fsck -y  /dev/sda5
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Clang-Format 格式化代码</title>
      <link>https://lifeislife.cn/posts/clang-format%E6%A0%BC%E5%BC%8F%E5%8C%96%E4%BB%A3%E7%A0%81/</link>
      <pubDate>Wed, 01 Dec 2021 17:42:45 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/clang-format%E6%A0%BC%E5%BC%8F%E5%8C%96%E4%BB%A3%E7%A0%81/</guid>
      <description>&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;
&lt;h3 id=&#34;linux&#34;&gt;Linux&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install clang-format
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;windows&#34;&gt;windows&lt;/h3&gt;
&lt;p&gt;每每到这时候就越能感受到用 Linux 作为开发环境的优势，Windows 安装就稍显复杂了。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;你可以选择安装完整的 LLVM，在&lt;code&gt;bin&lt;/code&gt;目录可以看到&lt;code&gt;clang-format.exe&lt;/code&gt;。安装完后，将 &lt;code&gt;bin&lt;/code&gt; 目录&lt;strong&gt;添加到环境变量&lt;/strong&gt;中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;你也可以只下载&lt;code&gt;clang-format.exe&lt;/code&gt;，从&lt;a href=&#34;https://llvm.org/builds/&#34;&gt;LLVM Snapshot Builds&lt;/a&gt;下载安装包。在下载页面的底部。同样你需要将单独下载的文件&lt;strong&gt;加入到环境变量&lt;/strong&gt;中。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208271559281.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208271559281.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;使用&#34;&gt;使用&lt;/h2&gt;
&lt;h3 id=&#34;入门使用&#34;&gt;入门使用&lt;/h3&gt;
&lt;p&gt;Linux 可以直接命令行，使用以 LLVM 代码风格格式化&lt;code&gt;main.cpp&lt;/code&gt;, 结果直接写到&lt;code&gt;main.cpp&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;clang g-format -i main.cpp -style&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;LLVM
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;进阶配置&#34;&gt;进阶配置&lt;/h3&gt;
&lt;p&gt;如果每次编码都命令行执行一遍那也太麻烦了，而且每次修改也不止一个文件。最好的方式就是每次保存文件时自动格式化。比如 VSCode 已经内置了&lt;code&gt;Clang-Format&lt;/code&gt;稍作配置即可实现，接下来介绍几种常见 IDE 如何配置&lt;code&gt;Clang-Format&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id=&#34;vscode&#34;&gt;VSCode&lt;/h4&gt;
&lt;p&gt;VSCode 最常用，因为内置了&lt;code&gt;Clang-Format&lt;/code&gt;也最容易配置。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;安装&lt;code&gt;C/C++&lt;/code&gt;插件，&lt;code&gt;Ctrl+Shift+X&lt;/code&gt;打开应用商店，搜索&lt;code&gt;C/C++&lt;/code&gt;找到下图插件，安装后会自动安装&lt;code&gt;Clang-Format&lt;/code&gt;程序，无需单独下载。默认安装路径为：
&lt;code&gt;C:\Users\(你的用户名)\.vscode\extensions\ms-vscode.cpptools-1.7.1\LLVM\bin\clang-format.exe&lt;/code&gt;。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012311818.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012311818.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/li&gt;
&lt;li&gt;打开设置页面（左下角齿轮 - 设置），搜索&lt;code&gt;format&lt;/code&gt;，勾选&lt;code&gt;Format On Save&lt;/code&gt;，每次保存文件时自动格式化文档。下方的设置是决定每次格式化是整个文档，还是做过修改的内容。默认是&lt;code&gt;file&lt;/code&gt;，对整个文档进行格式化。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012304766.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012304766.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/li&gt;
&lt;li&gt;仍在设置页面搜索&lt;code&gt;Clang&lt;/code&gt;，配置如下。&lt;code&gt;.clang-format&lt;/code&gt;文件最后详解。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012321838.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012321838.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/li&gt;
&lt;li&gt;效果图


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012327867.gif&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012327867.gif&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;qtcreator&#34;&gt;QtCreator&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;安装&lt;code&gt;Beautifier&lt;/code&gt;插件：帮助（&lt;code&gt;Help&lt;/code&gt;）-关于插件（&lt;code&gt;About Plugins&lt;/code&gt;）- &lt;code&gt;Beautifier&lt;/code&gt;勾选，重启 QtCreator。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202183720.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202183720.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/li&gt;
&lt;li&gt;工具（Tool）- &lt;code&gt;Beautifier&lt;/code&gt;，配置如图。该配置，保存文档时自动格式化，并选择&lt;code&gt;Clang-Format&lt;/code&gt;作为格式化工具。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202184119.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202184119.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
配置&lt;code&gt;Clang-Format&lt;/code&gt;程序路径，如果开头已经&lt;code&gt;apt install&lt;/code&gt;安装过，这里会自动补全。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202184247.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202184247.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Use predefined style&lt;/code&gt;可以选择内置的一些代码风格，如&lt;code&gt;LLVM&lt;/code&gt;，&lt;code&gt;Google&lt;/code&gt;等。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Use customized style&lt;/code&gt;使用自定义的一些代码风格。点击添加（&lt;code&gt;Add&lt;/code&gt;）将配置文件粘贴进去即可，具体配置文件见最后。&lt;/li&gt;
&lt;li&gt;别忘了点击&lt;code&gt;OK&lt;/code&gt;保存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;eclipse&#34;&gt;Eclipse&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安装&lt;code&gt;cppstyle&lt;/code&gt;插件：Help - Eclipse Marketplace - 搜索&lt;code&gt;cppstyle&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;下载&lt;code&gt;cpplint&lt;/code&gt;。
可以去github上下载&lt;a href=&#34;https://github.com/google/styleguide&#34;&gt;cpplint的源码&lt;/a&gt;，下载完之后解压放到某个目录下。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在&lt;code&gt;Window&lt;/code&gt; - &lt;code&gt;Preferences&lt;/code&gt; - &lt;code&gt;C/C++&lt;/code&gt; - &lt;code&gt;CppStyle&lt;/code&gt;页面把&lt;code&gt;clang-format&lt;/code&gt;的路径添加进去，然后把&lt;code&gt;cpplint&lt;/code&gt;的目录指向刚才下载的&lt;code&gt;styleguide&lt;/code&gt;目录下的&lt;code&gt;cpplint/cpplint.py&lt;/code&gt;就可以了。勾选下面的&lt;code&gt;Enable cpplint&lt;/code&gt;，&lt;code&gt;Run clang-format on file save&lt;/code&gt;，然后点击&lt;code&gt;Apply and Close&lt;/code&gt;保存修改并退出。如下图所示。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202190912.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202190912.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;此时再保存代码，将会出现如下错误，因为我们还未给当前项目编写配置文件&lt;code&gt;.clang-format&lt;/code&gt;。将最后一章提到的配置文件放到当前项目的下即可，程序会自动搜索。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Cannot find .clang-format or _clang-format configuration file under any level parent directories of path.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Clang-format will default to Google style.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;配置简介&#34;&gt;配置简介&lt;/h2&gt;
&lt;p&gt;上文多次提到了&lt;code&gt;.clang-format&lt;/code&gt;配置文件，该文件决定了代码如何格式化，现在来介绍如何使用该文件。&lt;/p&gt;
&lt;h3 id=&#34;导出clang-format文件&#34;&gt;导出&lt;code&gt;.clang-format&lt;/code&gt;文件&lt;/h3&gt;
&lt;p&gt;如果重新编写一份配置文件，需要考虑的东西太多，&lt;code&gt;clang-format&lt;/code&gt;内置了一些常见风格，我们可以根据已有的配置文件稍作修改，形成自己的代码风格。所以我们先导出一份内置的配置文件。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;clang-format -style&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;可选格式名 -dump-config &amp;gt; .clang-format
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 可选格式最好写预设那那几个写最接近你想要的格式。比如我想要接近 Google C++ style 的。我就写-style=google&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;各个选项的含义&#34;&gt;各个选项的含义&lt;/h3&gt;
&lt;p&gt;这里给出了配置的含义，感兴趣也可以查看官方文档，还提供了一些有案例，描述更清晰。&lt;/p&gt;
&lt;p&gt;一些比较明显的代码分格区别&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 括号是分行，还是不分行，只有当 BreakBeforeBraces 设置为 Custom 时才有效
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BraceWrapping:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterCaseLabel:  true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  # class 定义后面
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterClass:      true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  # 控制语句后面
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterControlStatement: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterEnum:       true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterFunction:   true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterNamespace:  true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterObjCDeclaration: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterStruct:     true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterUnion:      true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterExternBlock: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  BeforeCatch:     true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  BeforeElse:      true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  # 缩进大括号，if else 语句后面的括号缩进
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  IndentBraces:    false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  SplitEmptyFunction: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  SplitEmptyRecord: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  SplitEmptyNamespace: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakBeforeBinaryOperators: None
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakBeforeBraces: Custom
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# tab 宽度
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TabWidth: 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 换行缩进字符数
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IndentWidth:     4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 宏定义对齐
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignConsecutiveMacros: AcrossEmptyLinesAndComments
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;基于LLVM代码风格修改的个人使用版本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Language:        Cpp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# BasedOnStyle:  LLVM
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AccessModifierOffset: -2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignAfterOpenBracket: Align
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 宏定义对齐
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignConsecutiveMacros: AcrossEmptyLinesAndComments
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignConsecutiveAssignments: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignConsecutiveDeclarations: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignConsecutiveBitFields: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignEscapedNewlines: Right
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignOperands:   true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignTrailingComments: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowAllArgumentsOnNextLine: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowAllConstructorInitializersOnNextLine: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowAllParametersOfDeclarationOnNextLine: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowShortBlocksOnASingleLine: Never
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowShortCaseLabelsOnASingleLine: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 是否允许短方法单行，只有一行的函数将不会分行，直接写在函数名后
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowShortFunctionsOnASingleLine: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowShortLambdasOnASingleLine: All
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowShortIfStatementsOnASingleLine: Never
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AllowShortLoopsOnASingleLine: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlwaysBreakAfterDefinitionReturnType: None
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlwaysBreakAfterReturnType: None
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlwaysBreakBeforeMultilineStrings: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlwaysBreakTemplateDeclarations: MultiLine
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BinPackArguments: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BinPackParameters: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 括号是分行，还是不分行，只有当 BreakBeforeBraces 设置为 Custom 时才有效
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BraceWrapping:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterCaseLabel:  true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  # class 定义后面
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterClass:      true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  # 控制语句后面
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterControlStatement: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterEnum:       true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterFunction:   true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterNamespace:  true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterObjCDeclaration: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterStruct:     true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterUnion:      true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  AfterExternBlock: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  BeforeCatch:     true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  BeforeElse:      true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  # 缩进大括号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  IndentBraces:    false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  SplitEmptyFunction: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  SplitEmptyRecord: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  SplitEmptyNamespace: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakBeforeBinaryOperators: None
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakBeforeBraces: Custom
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakBeforeInheritanceComma: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakInheritanceList: BeforeColon
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakBeforeTernaryOperators: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakConstructorInitializersBeforeComma: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakConstructorInitializers: BeforeColon
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakAfterJavaFieldAnnotations: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BreakStringLiterals: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ColumnLimit:     100
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;CommentPragmas:  &amp;#39;^ IWYU pragma:&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;CompactNamespaces: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ConstructorInitializerAllOnOneLineOrOnePerLine: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ConstructorInitializerIndentWidth: 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ContinuationIndentWidth: 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Cpp11BracedListStyle: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DeriveLineEnding: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DerivePointerAlignment: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;DisableFormat:   false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ExperimentalAutoDetectBinPacking: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;FixNamespaceComments: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ForEachMacros:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - foreach
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Q_FOREACH
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - BOOST_FOREACH
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IncludeBlocks:   Preserve
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IncludeCategories:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Regex:           &amp;#39;^&amp;#34;(llvm|llvm-c|clang|clang-c)/&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Priority:        2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    SortPriority:    0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Regex:           &amp;#39;^(&amp;lt;|&amp;#34;(gtest|gmock|isl|json)/)&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Priority:        3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    SortPriority:    0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Regex:           &amp;#39;.*&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Priority:        1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    SortPriority:    0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IncludeIsMainRegex: &amp;#39;(Test)?$&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IncludeIsMainSourceRegex: &amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IndentCaseLabels: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IndentGotoLabels: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IndentPPDirectives: None
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 换行缩进字符数
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IndentWidth:     4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IndentWrappedFunctionNames: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;JavaScriptQuotes: Leave
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;JavaScriptWrapImports: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;KeepEmptyLinesAtTheStartOfBlocks: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MacroBlockBegin: &amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MacroBlockEnd:   &amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MaxEmptyLinesToKeep: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NamespaceIndentation: None
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ObjCBinPackProtocolList: Auto
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ObjCBlockIndentWidth: 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ObjCSpaceAfterProperty: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ObjCSpaceBeforeProtocolList: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PenaltyBreakAssignment: 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PenaltyBreakBeforeFirstCallParameter: 19
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PenaltyBreakComment: 300
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PenaltyBreakFirstLessLess: 120
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PenaltyBreakString: 1000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PenaltyBreakTemplateDeclaration: 10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PenaltyExcessCharacter: 1000000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PenaltyReturnTypeOnItsOwnLine: 60
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PointerAlignment: Right
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ReflowComments:  true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SortIncludes:    true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SortUsingDeclarations: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceAfterCStyleCast: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceAfterLogicalNot: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceAfterTemplateKeyword: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceBeforeAssignmentOperators: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceBeforeCpp11BracedList: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceBeforeCtorInitializerColon: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceBeforeInheritanceColon: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceBeforeParens: ControlStatements
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceBeforeRangeBasedForLoopColon: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceInEmptyBlock: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceInEmptyParentheses: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpacesBeforeTrailingComments: 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpacesInAngles:  false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpacesInConditionalStatement: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpacesInContainerLiterals: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpacesInCStyleCastParentheses: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpacesInParentheses: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpacesInSquareBrackets: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SpaceBeforeSquareBrackets: false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Standard:        Latest
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;StatementMacros:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - Q_UNUSED
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - QT_REQUIRE_VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TabWidth:        8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;UseCRLF:         false
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;UseTab:          Never
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;格式化最新的commit代码&#34;&gt;格式化最新的commit代码&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;clang-format&lt;/code&gt;还提供一个&lt;code&gt;clang-format-diff.py&lt;/code&gt;脚本，用来格式化&lt;code&gt;patch&lt;/code&gt;，&lt;code&gt;code review&lt;/code&gt;提交代码前，跑一遍下面的代码。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;// 格式化最新的 commit，并直接在原文件上修改
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git diff -U0 HEAD^ &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; clang-format-diff.py -i -p1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;常见问题&#34;&gt;常见问题&lt;/h3&gt;
&lt;h4 id=&#34;如何看懂官方文档并编写配置文件&#34;&gt;如何看懂官方文档并编写配置文件&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://clang.llvm.org/docs/ClangFormatStyleOptions.html&#34;&gt;官方文档&lt;/a&gt;里有各种设置的示例代码，即使不知道想要的格式化是哪个配置参数，翻一翻官方文档是示例大概率能找到。那么找到了想要的配置参数，如何在文件里配置呢？&lt;/p&gt;
&lt;p&gt;以宏定义对齐为例。我们想要宏定义的值保持对齐的状态，如下一节图片所示。可以翻一遍官方文档，可以发现这个示例代码对应的参数可能是我们想要的，&lt;code&gt;AlignConsecutiveMacros&lt;/code&gt;翻译为&lt;strong&gt;对齐连续的宏定义&lt;/strong&gt;。那应该八九不离十了。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112202021134.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112202021134.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;找到了参数如何编写配置文件呢？可以继续看这个参数下面的更多示例，每一个示例都对应一个配置可能值&lt;code&gt;Possible values&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ACS_None&lt;/code&gt; (in configuration: &lt;code&gt;None&lt;/code&gt;)
Do not align macro definitions on consecutive lines.
&lt;code&gt;ACS_None&lt;/code&gt;为这个配置的缩写，&lt;code&gt;None&lt;/code&gt;表示在配置文件里的值。该配置表示不对宏定义进行对齐操作，在配置文件里可以添加如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignConsecutiveMacros: None
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ACS_Consecutive&lt;/code&gt; (in configuration: &lt;code&gt;Consecutive&lt;/code&gt;)
Align macro definitions on consecutive lines. This will result in formattings like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#define SHORT_NAME       42
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#define LONGER_NAME      0x007f
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#define EVEN_LONGER_NAME (2)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#define foo(x) (x * x)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/* some comment */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#define bar(y, z) (y + z)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ACS_Consecutive&lt;/code&gt;为这个配置的缩写，&lt;code&gt;Consecutive&lt;/code&gt;表示在配置文件里的值。该配置表示对连续的宏定义进行对齐，在配置文件里可以添加如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignConsecutiveMacros: Consecutive
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;宏定义对齐失效&#34;&gt;宏定义对齐失效&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 宏定义对齐
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;AlignConsecutiveMacros: AcrossEmptyLinesAndComments
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用宏定义对齐更详细的配置，可以&lt;a href=&#34;https://clang.llvm.org/docs/ClangFormatStyleOptions.html&#34;&gt;参考官方文档&lt;/a&gt;。使用该配置一定要使用等宽的字体，否则配置生效但是显示不正确。
比如我是用&lt;strong&gt;微软雅黑&lt;/strong&gt;字体作为编码字体，因为该字体每个字符不等宽，导致格式化正确，但是显示不正确。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112201954096.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112201954096.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;如果将字体换位等宽字体如常用的&lt;strong&gt;Consolas&lt;/strong&gt;，就可以正常显示。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112201958869.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112201958869.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="安装">安装</h2>
<h3 id="linux">Linux</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get install clang-format
</span></span></code></pre></div><h3 id="windows">windows</h3>
<p>每每到这时候就越能感受到用 Linux 作为开发环境的优势，Windows 安装就稍显复杂了。</p>
<ol>
<li>
<p>你可以选择安装完整的 LLVM，在<code>bin</code>目录可以看到<code>clang-format.exe</code>。安装完后，将 <code>bin</code> 目录<strong>添加到环境变量</strong>中。</p>
</li>
<li>
<p>你也可以只下载<code>clang-format.exe</code>，从<a href="https://llvm.org/builds/">LLVM Snapshot Builds</a>下载安装包。在下载页面的底部。同样你需要将单独下载的文件<strong>加入到环境变量</strong>中。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208271559281.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208271559281.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
</li>
</ol>
<h2 id="使用">使用</h2>
<h3 id="入门使用">入门使用</h3>
<p>Linux 可以直接命令行，使用以 LLVM 代码风格格式化<code>main.cpp</code>, 结果直接写到<code>main.cpp</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">clang g-format -i main.cpp -style<span class="o">=</span>LLVM
</span></span></code></pre></div><h3 id="进阶配置">进阶配置</h3>
<p>如果每次编码都命令行执行一遍那也太麻烦了，而且每次修改也不止一个文件。最好的方式就是每次保存文件时自动格式化。比如 VSCode 已经内置了<code>Clang-Format</code>稍作配置即可实现，接下来介绍几种常见 IDE 如何配置<code>Clang-Format</code>。</p>
<h4 id="vscode">VSCode</h4>
<p>VSCode 最常用，因为内置了<code>Clang-Format</code>也最容易配置。</p>
<ul>
<li>安装<code>C/C++</code>插件，<code>Ctrl+Shift+X</code>打开应用商店，搜索<code>C/C++</code>找到下图插件，安装后会自动安装<code>Clang-Format</code>程序，无需单独下载。默认安装路径为：
<code>C:\Users\(你的用户名)\.vscode\extensions\ms-vscode.cpptools-1.7.1\LLVM\bin\clang-format.exe</code>。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012311818.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012311818.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></li>
<li>打开设置页面（左下角齿轮 - 设置），搜索<code>format</code>，勾选<code>Format On Save</code>，每次保存文件时自动格式化文档。下方的设置是决定每次格式化是整个文档，还是做过修改的内容。默认是<code>file</code>，对整个文档进行格式化。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012304766.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012304766.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></li>
<li>仍在设置页面搜索<code>Clang</code>，配置如下。<code>.clang-format</code>文件最后详解。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012321838.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012321838.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></li>
<li>效果图


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012327867.gif">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112012327867.gif" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></li>
</ul>
<h4 id="qtcreator">QtCreator</h4>
<ul>
<li>安装<code>Beautifier</code>插件：帮助（<code>Help</code>）-关于插件（<code>About Plugins</code>）- <code>Beautifier</code>勾选，重启 QtCreator。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202183720.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202183720.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></li>
<li>工具（Tool）- <code>Beautifier</code>，配置如图。该配置，保存文档时自动格式化，并选择<code>Clang-Format</code>作为格式化工具。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202184119.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202184119.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>
配置<code>Clang-Format</code>程序路径，如果开头已经<code>apt install</code>安装过，这里会自动补全。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202184247.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202184247.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></li>
<li><code>Use predefined style</code>可以选择内置的一些代码风格，如<code>LLVM</code>，<code>Google</code>等。</li>
<li><code>Use customized style</code>使用自定义的一些代码风格。点击添加（<code>Add</code>）将配置文件粘贴进去即可，具体配置文件见最后。</li>
<li>别忘了点击<code>OK</code>保存。</li>
</ul>
<h4 id="eclipse">Eclipse</h4>
<ul>
<li>
<p>安装<code>cppstyle</code>插件：Help - Eclipse Marketplace - 搜索<code>cppstyle</code>。</p>
</li>
<li>
<p>下载<code>cpplint</code>。
可以去github上下载<a href="https://github.com/google/styleguide">cpplint的源码</a>，下载完之后解压放到某个目录下。</p>
</li>
<li>
<p>在<code>Window</code> - <code>Preferences</code> - <code>C/C++</code> - <code>CppStyle</code>页面把<code>clang-format</code>的路径添加进去，然后把<code>cpplint</code>的目录指向刚才下载的<code>styleguide</code>目录下的<code>cpplint/cpplint.py</code>就可以了。勾选下面的<code>Enable cpplint</code>，<code>Run clang-format on file save</code>，然后点击<code>Apply and Close</code>保存修改并退出。如下图所示。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202190912.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211202190912.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
</li>
<li>
<p>此时再保存代码，将会出现如下错误，因为我们还未给当前项目编写配置文件<code>.clang-format</code>。将最后一章提到的配置文件放到当前项目的下即可，程序会自动搜索。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Cannot find .clang-format or _clang-format configuration file under any level parent directories of path.
</span></span><span class="line"><span class="cl">Clang-format will default to Google style.
</span></span></code></pre></div></li>
</ul>
<h2 id="配置简介">配置简介</h2>
<p>上文多次提到了<code>.clang-format</code>配置文件，该文件决定了代码如何格式化，现在来介绍如何使用该文件。</p>
<h3 id="导出clang-format文件">导出<code>.clang-format</code>文件</h3>
<p>如果重新编写一份配置文件，需要考虑的东西太多，<code>clang-format</code>内置了一些常见风格，我们可以根据已有的配置文件稍作修改，形成自己的代码风格。所以我们先导出一份内置的配置文件。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">clang-format -style<span class="o">=</span>可选格式名 -dump-config &gt; .clang-format
</span></span><span class="line"><span class="cl"><span class="c1"># 可选格式最好写预设那那几个写最接近你想要的格式。比如我想要接近 Google C++ style 的。我就写-style=google</span>
</span></span></code></pre></div><h3 id="各个选项的含义">各个选项的含义</h3>
<p>这里给出了配置的含义，感兴趣也可以查看官方文档，还提供了一些有案例，描述更清晰。</p>
<p>一些比较明显的代码分格区别</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 括号是分行，还是不分行，只有当 BreakBeforeBraces 设置为 Custom 时才有效
</span></span><span class="line"><span class="cl">BraceWrapping:
</span></span><span class="line"><span class="cl">  AfterCaseLabel:  true
</span></span><span class="line"><span class="cl">  # class 定义后面
</span></span><span class="line"><span class="cl">  AfterClass:      true
</span></span><span class="line"><span class="cl">  # 控制语句后面
</span></span><span class="line"><span class="cl">  AfterControlStatement: true
</span></span><span class="line"><span class="cl">  AfterEnum:       true
</span></span><span class="line"><span class="cl">  AfterFunction:   true
</span></span><span class="line"><span class="cl">  AfterNamespace:  true
</span></span><span class="line"><span class="cl">  AfterObjCDeclaration: true
</span></span><span class="line"><span class="cl">  AfterStruct:     true
</span></span><span class="line"><span class="cl">  AfterUnion:      true
</span></span><span class="line"><span class="cl">  AfterExternBlock: true
</span></span><span class="line"><span class="cl">  BeforeCatch:     true
</span></span><span class="line"><span class="cl">  BeforeElse:      true
</span></span><span class="line"><span class="cl">  # 缩进大括号，if else 语句后面的括号缩进
</span></span><span class="line"><span class="cl">  IndentBraces:    false
</span></span><span class="line"><span class="cl">  SplitEmptyFunction: true
</span></span><span class="line"><span class="cl">  SplitEmptyRecord: true
</span></span><span class="line"><span class="cl">  SplitEmptyNamespace: true
</span></span><span class="line"><span class="cl">BreakBeforeBinaryOperators: None
</span></span><span class="line"><span class="cl">BreakBeforeBraces: Custom
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># tab 宽度
</span></span><span class="line"><span class="cl">TabWidth: 4
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 换行缩进字符数
</span></span><span class="line"><span class="cl">IndentWidth:     4
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 宏定义对齐
</span></span><span class="line"><span class="cl">AlignConsecutiveMacros: AcrossEmptyLinesAndComments
</span></span></code></pre></div><p>基于LLVM代码风格修改的个人使用版本：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">Language:        Cpp
</span></span><span class="line"><span class="cl"># BasedOnStyle:  LLVM
</span></span><span class="line"><span class="cl">AccessModifierOffset: -2
</span></span><span class="line"><span class="cl">AlignAfterOpenBracket: Align
</span></span><span class="line"><span class="cl"># 宏定义对齐
</span></span><span class="line"><span class="cl">AlignConsecutiveMacros: AcrossEmptyLinesAndComments
</span></span><span class="line"><span class="cl">AlignConsecutiveAssignments: true
</span></span><span class="line"><span class="cl">AlignConsecutiveDeclarations: true
</span></span><span class="line"><span class="cl">AlignConsecutiveBitFields: true
</span></span><span class="line"><span class="cl">AlignEscapedNewlines: Right
</span></span><span class="line"><span class="cl">AlignOperands:   true
</span></span><span class="line"><span class="cl">AlignTrailingComments: true
</span></span><span class="line"><span class="cl">AllowAllArgumentsOnNextLine: true
</span></span><span class="line"><span class="cl">AllowAllConstructorInitializersOnNextLine: true
</span></span><span class="line"><span class="cl">AllowAllParametersOfDeclarationOnNextLine: true
</span></span><span class="line"><span class="cl">AllowShortBlocksOnASingleLine: Never
</span></span><span class="line"><span class="cl">AllowShortCaseLabelsOnASingleLine: false
</span></span><span class="line"><span class="cl"># 是否允许短方法单行，只有一行的函数将不会分行，直接写在函数名后
</span></span><span class="line"><span class="cl">AllowShortFunctionsOnASingleLine: false
</span></span><span class="line"><span class="cl">AllowShortLambdasOnASingleLine: All
</span></span><span class="line"><span class="cl">AllowShortIfStatementsOnASingleLine: Never
</span></span><span class="line"><span class="cl">AllowShortLoopsOnASingleLine: false
</span></span><span class="line"><span class="cl">AlwaysBreakAfterDefinitionReturnType: None
</span></span><span class="line"><span class="cl">AlwaysBreakAfterReturnType: None
</span></span><span class="line"><span class="cl">AlwaysBreakBeforeMultilineStrings: false
</span></span><span class="line"><span class="cl">AlwaysBreakTemplateDeclarations: MultiLine
</span></span><span class="line"><span class="cl">BinPackArguments: true
</span></span><span class="line"><span class="cl">BinPackParameters: true
</span></span><span class="line"><span class="cl"># 括号是分行，还是不分行，只有当 BreakBeforeBraces 设置为 Custom 时才有效
</span></span><span class="line"><span class="cl">BraceWrapping:
</span></span><span class="line"><span class="cl">  AfterCaseLabel:  true
</span></span><span class="line"><span class="cl">  # class 定义后面
</span></span><span class="line"><span class="cl">  AfterClass:      true
</span></span><span class="line"><span class="cl">  # 控制语句后面
</span></span><span class="line"><span class="cl">  AfterControlStatement: true
</span></span><span class="line"><span class="cl">  AfterEnum:       true
</span></span><span class="line"><span class="cl">  AfterFunction:   true
</span></span><span class="line"><span class="cl">  AfterNamespace:  true
</span></span><span class="line"><span class="cl">  AfterObjCDeclaration: true
</span></span><span class="line"><span class="cl">  AfterStruct:     true
</span></span><span class="line"><span class="cl">  AfterUnion:      true
</span></span><span class="line"><span class="cl">  AfterExternBlock: false
</span></span><span class="line"><span class="cl">  BeforeCatch:     true
</span></span><span class="line"><span class="cl">  BeforeElse:      true
</span></span><span class="line"><span class="cl">  # 缩进大括号
</span></span><span class="line"><span class="cl">  IndentBraces:    false
</span></span><span class="line"><span class="cl">  SplitEmptyFunction: true
</span></span><span class="line"><span class="cl">  SplitEmptyRecord: true
</span></span><span class="line"><span class="cl">  SplitEmptyNamespace: true
</span></span><span class="line"><span class="cl">BreakBeforeBinaryOperators: None
</span></span><span class="line"><span class="cl">BreakBeforeBraces: Custom
</span></span><span class="line"><span class="cl">BreakBeforeInheritanceComma: false
</span></span><span class="line"><span class="cl">BreakInheritanceList: BeforeColon
</span></span><span class="line"><span class="cl">BreakBeforeTernaryOperators: true
</span></span><span class="line"><span class="cl">BreakConstructorInitializersBeforeComma: false
</span></span><span class="line"><span class="cl">BreakConstructorInitializers: BeforeColon
</span></span><span class="line"><span class="cl">BreakAfterJavaFieldAnnotations: false
</span></span><span class="line"><span class="cl">BreakStringLiterals: true
</span></span><span class="line"><span class="cl">ColumnLimit:     100
</span></span><span class="line"><span class="cl">CommentPragmas:  &#39;^ IWYU pragma:&#39;
</span></span><span class="line"><span class="cl">CompactNamespaces: false
</span></span><span class="line"><span class="cl">ConstructorInitializerAllOnOneLineOrOnePerLine: false
</span></span><span class="line"><span class="cl">ConstructorInitializerIndentWidth: 4
</span></span><span class="line"><span class="cl">ContinuationIndentWidth: 4
</span></span><span class="line"><span class="cl">Cpp11BracedListStyle: true
</span></span><span class="line"><span class="cl">DeriveLineEnding: true
</span></span><span class="line"><span class="cl">DerivePointerAlignment: false
</span></span><span class="line"><span class="cl">DisableFormat:   false
</span></span><span class="line"><span class="cl">ExperimentalAutoDetectBinPacking: false
</span></span><span class="line"><span class="cl">FixNamespaceComments: true
</span></span><span class="line"><span class="cl">ForEachMacros:
</span></span><span class="line"><span class="cl">  - foreach
</span></span><span class="line"><span class="cl">  - Q_FOREACH
</span></span><span class="line"><span class="cl">  - BOOST_FOREACH
</span></span><span class="line"><span class="cl">IncludeBlocks:   Preserve
</span></span><span class="line"><span class="cl">IncludeCategories:
</span></span><span class="line"><span class="cl">  - Regex:           &#39;^&#34;(llvm|llvm-c|clang|clang-c)/&#39;
</span></span><span class="line"><span class="cl">    Priority:        2
</span></span><span class="line"><span class="cl">    SortPriority:    0
</span></span><span class="line"><span class="cl">  - Regex:           &#39;^(&lt;|&#34;(gtest|gmock|isl|json)/)&#39;
</span></span><span class="line"><span class="cl">    Priority:        3
</span></span><span class="line"><span class="cl">    SortPriority:    0
</span></span><span class="line"><span class="cl">  - Regex:           &#39;.*&#39;
</span></span><span class="line"><span class="cl">    Priority:        1
</span></span><span class="line"><span class="cl">    SortPriority:    0
</span></span><span class="line"><span class="cl">IncludeIsMainRegex: &#39;(Test)?$&#39;
</span></span><span class="line"><span class="cl">IncludeIsMainSourceRegex: &#39;&#39;
</span></span><span class="line"><span class="cl">IndentCaseLabels: false
</span></span><span class="line"><span class="cl">IndentGotoLabels: true
</span></span><span class="line"><span class="cl">IndentPPDirectives: None
</span></span><span class="line"><span class="cl"># 换行缩进字符数
</span></span><span class="line"><span class="cl">IndentWidth:     4
</span></span><span class="line"><span class="cl">IndentWrappedFunctionNames: false
</span></span><span class="line"><span class="cl">JavaScriptQuotes: Leave
</span></span><span class="line"><span class="cl">JavaScriptWrapImports: true
</span></span><span class="line"><span class="cl">KeepEmptyLinesAtTheStartOfBlocks: true
</span></span><span class="line"><span class="cl">MacroBlockBegin: &#39;&#39;
</span></span><span class="line"><span class="cl">MacroBlockEnd:   &#39;&#39;
</span></span><span class="line"><span class="cl">MaxEmptyLinesToKeep: 1
</span></span><span class="line"><span class="cl">NamespaceIndentation: None
</span></span><span class="line"><span class="cl">ObjCBinPackProtocolList: Auto
</span></span><span class="line"><span class="cl">ObjCBlockIndentWidth: 0
</span></span><span class="line"><span class="cl">ObjCSpaceAfterProperty: false
</span></span><span class="line"><span class="cl">ObjCSpaceBeforeProtocolList: true
</span></span><span class="line"><span class="cl">PenaltyBreakAssignment: 2
</span></span><span class="line"><span class="cl">PenaltyBreakBeforeFirstCallParameter: 19
</span></span><span class="line"><span class="cl">PenaltyBreakComment: 300
</span></span><span class="line"><span class="cl">PenaltyBreakFirstLessLess: 120
</span></span><span class="line"><span class="cl">PenaltyBreakString: 1000
</span></span><span class="line"><span class="cl">PenaltyBreakTemplateDeclaration: 10
</span></span><span class="line"><span class="cl">PenaltyExcessCharacter: 1000000
</span></span><span class="line"><span class="cl">PenaltyReturnTypeOnItsOwnLine: 60
</span></span><span class="line"><span class="cl">PointerAlignment: Right
</span></span><span class="line"><span class="cl">ReflowComments:  true
</span></span><span class="line"><span class="cl">SortIncludes:    true
</span></span><span class="line"><span class="cl">SortUsingDeclarations: true
</span></span><span class="line"><span class="cl">SpaceAfterCStyleCast: false
</span></span><span class="line"><span class="cl">SpaceAfterLogicalNot: false
</span></span><span class="line"><span class="cl">SpaceAfterTemplateKeyword: true
</span></span><span class="line"><span class="cl">SpaceBeforeAssignmentOperators: true
</span></span><span class="line"><span class="cl">SpaceBeforeCpp11BracedList: false
</span></span><span class="line"><span class="cl">SpaceBeforeCtorInitializerColon: true
</span></span><span class="line"><span class="cl">SpaceBeforeInheritanceColon: true
</span></span><span class="line"><span class="cl">SpaceBeforeParens: ControlStatements
</span></span><span class="line"><span class="cl">SpaceBeforeRangeBasedForLoopColon: true
</span></span><span class="line"><span class="cl">SpaceInEmptyBlock: false
</span></span><span class="line"><span class="cl">SpaceInEmptyParentheses: false
</span></span><span class="line"><span class="cl">SpacesBeforeTrailingComments: 1
</span></span><span class="line"><span class="cl">SpacesInAngles:  false
</span></span><span class="line"><span class="cl">SpacesInConditionalStatement: false
</span></span><span class="line"><span class="cl">SpacesInContainerLiterals: true
</span></span><span class="line"><span class="cl">SpacesInCStyleCastParentheses: false
</span></span><span class="line"><span class="cl">SpacesInParentheses: false
</span></span><span class="line"><span class="cl">SpacesInSquareBrackets: false
</span></span><span class="line"><span class="cl">SpaceBeforeSquareBrackets: false
</span></span><span class="line"><span class="cl">Standard:        Latest
</span></span><span class="line"><span class="cl">StatementMacros:
</span></span><span class="line"><span class="cl">  - Q_UNUSED
</span></span><span class="line"><span class="cl">  - QT_REQUIRE_VERSION
</span></span><span class="line"><span class="cl">TabWidth:        8
</span></span><span class="line"><span class="cl">UseCRLF:         false
</span></span><span class="line"><span class="cl">UseTab:          Never
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></div><h3 id="格式化最新的commit代码">格式化最新的commit代码</h3>
<p><code>clang-format</code>还提供一个<code>clang-format-diff.py</code>脚本，用来格式化<code>patch</code>，<code>code review</code>提交代码前，跑一遍下面的代码。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">// 格式化最新的 commit，并直接在原文件上修改
</span></span><span class="line"><span class="cl">git diff -U0 HEAD^ <span class="p">|</span> clang-format-diff.py -i -p1
</span></span></code></pre></div><h3 id="常见问题">常见问题</h3>
<h4 id="如何看懂官方文档并编写配置文件">如何看懂官方文档并编写配置文件</h4>
<p><a href="https://clang.llvm.org/docs/ClangFormatStyleOptions.html">官方文档</a>里有各种设置的示例代码，即使不知道想要的格式化是哪个配置参数，翻一翻官方文档是示例大概率能找到。那么找到了想要的配置参数，如何在文件里配置呢？</p>
<p>以宏定义对齐为例。我们想要宏定义的值保持对齐的状态，如下一节图片所示。可以翻一遍官方文档，可以发现这个示例代码对应的参数可能是我们想要的，<code>AlignConsecutiveMacros</code>翻译为<strong>对齐连续的宏定义</strong>。那应该八九不离十了。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112202021134.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112202021134.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>找到了参数如何编写配置文件呢？可以继续看这个参数下面的更多示例，每一个示例都对应一个配置可能值<code>Possible values</code>。</p>
<ul>
<li>
<p><code>ACS_None</code> (in configuration: <code>None</code>)
Do not align macro definitions on consecutive lines.
<code>ACS_None</code>为这个配置的缩写，<code>None</code>表示在配置文件里的值。该配置表示不对宏定义进行对齐操作，在配置文件里可以添加如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">AlignConsecutiveMacros: None
</span></span></code></pre></div></li>
<li>
<p><code>ACS_Consecutive</code> (in configuration: <code>Consecutive</code>)
Align macro definitions on consecutive lines. This will result in formattings like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">#define SHORT_NAME       42
</span></span><span class="line"><span class="cl">#define LONGER_NAME      0x007f
</span></span><span class="line"><span class="cl">#define EVEN_LONGER_NAME (2)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">#define foo(x) (x * x)
</span></span><span class="line"><span class="cl">/* some comment */
</span></span><span class="line"><span class="cl">#define bar(y, z) (y + z)
</span></span></code></pre></div><p><code>ACS_Consecutive</code>为这个配置的缩写，<code>Consecutive</code>表示在配置文件里的值。该配置表示对连续的宏定义进行对齐，在配置文件里可以添加如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">AlignConsecutiveMacros: Consecutive
</span></span></code></pre></div></li>
</ul>
<h4 id="宏定义对齐失效">宏定义对齐失效</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 宏定义对齐
</span></span><span class="line"><span class="cl">AlignConsecutiveMacros: AcrossEmptyLinesAndComments
</span></span></code></pre></div><p>使用宏定义对齐更详细的配置，可以<a href="https://clang.llvm.org/docs/ClangFormatStyleOptions.html">参考官方文档</a>。使用该配置一定要使用等宽的字体，否则配置生效但是显示不正确。
比如我是用<strong>微软雅黑</strong>字体作为编码字体，因为该字体每个字符不等宽，导致格式化正确，但是显示不正确。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112201954096.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112201954096.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>如果将字体换位等宽字体如常用的<strong>Consolas</strong>，就可以正常显示。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112201958869.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202112201958869.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 文件删除仍然在 Trash 目录下占用空间，该如何删除 Trash 下的文件</title>
      <link>https://lifeislife.cn/posts/linux%E6%96%87%E4%BB%B6%E5%88%A0%E9%99%A4%E4%BB%8D%E7%84%B6%E5%9C%A8trash%E7%9B%AE%E5%BD%95%E4%B8%8B%E5%8D%A0%E7%94%A8%E7%A9%BA%E9%97%B4%E8%AF%A5%E5%A6%82%E4%BD%95%E5%88%A0%E9%99%A4trash%E4%B8%8B%E7%9A%84%E6%96%87%E4%BB%B6/</link>
      <pubDate>Thu, 25 Nov 2021 10:31:27 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%96%87%E4%BB%B6%E5%88%A0%E9%99%A4%E4%BB%8D%E7%84%B6%E5%9C%A8trash%E7%9B%AE%E5%BD%95%E4%B8%8B%E5%8D%A0%E7%94%A8%E7%A9%BA%E9%97%B4%E8%AF%A5%E5%A6%82%E4%BD%95%E5%88%A0%E9%99%A4trash%E4%B8%8B%E7%9A%84%E6%96%87%E4%BB%B6/</guid>
      <description>&lt;h2 id=&#34;保留现场&#34;&gt;保留现场&lt;/h2&gt;
&lt;h2 id=&#34;探究原因&#34;&gt;探究原因&lt;/h2&gt;
&lt;p&gt;查阅了一个&lt;a href=&#34;https://askubuntu.com/questions/351400/deleting-contents-of-local-share-trash-expunged&#34;&gt;网上的答案&lt;/a&gt;，大意就是，你删除了属于你的文件夹，但其中包含属于另一个用户的文件时，文件可能会卡住，就会在 Trash 目录里不会被彻底删除。&lt;/p&gt;
&lt;h2 id=&#34;解决方法&#34;&gt;解决方法&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo rm -rv /home/&amp;lt;your_username&amp;gt;/.local/share/Trash/expunged/*
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PS：发现一个好用的磁盘分析工具，Linux 内置应用&lt;code&gt;Disk Usage Analyzer&lt;/code&gt;。按&lt;code&gt;Win&lt;/code&gt;键后搜索框搜索即可打开。&lt;/p&gt;
&lt;p&gt;图形化的方式快速找到占用空间较大的目录，文件。可以右击直接删除。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211125102946.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211125102946.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="保留现场">保留现场</h2>
<h2 id="探究原因">探究原因</h2>
<p>查阅了一个<a href="https://askubuntu.com/questions/351400/deleting-contents-of-local-share-trash-expunged">网上的答案</a>，大意就是，你删除了属于你的文件夹，但其中包含属于另一个用户的文件时，文件可能会卡住，就会在 Trash 目录里不会被彻底删除。</p>
<h2 id="解决方法">解决方法</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo rm -rv /home/&lt;your_username&gt;/.local/share/Trash/expunged/*
</span></span></code></pre></div><p>PS：发现一个好用的磁盘分析工具，Linux 内置应用<code>Disk Usage Analyzer</code>。按<code>Win</code>键后搜索框搜索即可打开。</p>
<p>图形化的方式快速找到占用空间较大的目录，文件。可以右击直接删除。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211125102946.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211125102946.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 下将编译结果输出到文件</title>
      <link>https://lifeislife.cn/posts/linux%E4%B8%8B%E5%B0%86%E7%BC%96%E8%AF%91%E7%BB%93%E6%9E%9C%E8%BE%93%E5%87%BA%E5%88%B0%E6%96%87%E4%BB%B6/</link>
      <pubDate>Thu, 30 Sep 2021 15:18:32 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E4%B8%8B%E5%B0%86%E7%BC%96%E8%AF%91%E7%BB%93%E6%9E%9C%E8%BE%93%E5%87%BA%E5%88%B0%E6%96%87%E4%BB%B6/</guid>
      <description>&lt;p&gt;在命令行编译项目时，经常遇到编译结果太长，覆盖了最先输出的结果，此时就需要将结果输出到文件再查看。命令如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &amp;gt; make.log 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# make 编译命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# make.log 输出文件名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 2 文件描述符，标准错误&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;gt; 重定向符，输出&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;amp;1 文件描述符&amp;amp;，文件描述符1 标准输入&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该命令功能即将&lt;code&gt;make&lt;/code&gt;编译时输出，标准错误重定向为标准输入，写入到&lt;code&gt;make.log&lt;/code&gt;文件中。符号的含义可以参考&lt;a href=&#34;&#34;&gt;Linux 文件描述符&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>在命令行编译项目时，经常遇到编译结果太长，覆盖了最先输出的结果，此时就需要将结果输出到文件再查看。命令如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make &gt; make.log 2&gt;<span class="p">&amp;</span><span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="c1"># make 编译命令</span>
</span></span><span class="line"><span class="cl"><span class="c1"># make.log 输出文件名</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 2 文件描述符，标准错误</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &gt; 重定向符，输出</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &amp;1 文件描述符&amp;，文件描述符1 标准输入</span>
</span></span></code></pre></div><p>该命令功能即将<code>make</code>编译时输出，标准错误重定向为标准输入，写入到<code>make.log</code>文件中。符号的含义可以参考<a href="">Linux 文件描述符</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 文件描述符</title>
      <link>https://lifeislife.cn/posts/linux%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6/</link>
      <pubDate>Thu, 30 Sep 2021 11:13:02 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;Linux 中一切皆文件，比如 C++ 源文件、视频文件、Shell 脚本、可执行文件等，就连键盘、显示器、鼠标等硬件设备也都是文件。&lt;/p&gt;
&lt;p&gt;一个 Linux 进程可以打开成百上千个文件，为了表示和区分已经打开的文件，Linux 会给每个文件分配一个编号（一个 ID），这个编号就是一个整数，被称为&lt;strong&gt;文件描述符&lt;/strong&gt;（File Descriptor）。&lt;/p&gt;
&lt;h2 id=&#34;文件描述符是什么&#34;&gt;文件描述符是什么？&lt;/h2&gt;
&lt;p&gt;一个 Linux 进程启动后，会在内核空间中创建一个 &lt;code&gt;PCB&lt;/code&gt; 控制块，&lt;code&gt;PCB&lt;/code&gt; 内部有一个&lt;strong&gt;文件描述符表&lt;/strong&gt;（File descriptor table），记录着当前进程所有可用的文件描述符，也即当前进程所有打开的文件。&lt;/p&gt;
&lt;p&gt;除了文件描述符表，系统还需要维护另外两张表：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打开文件表（Open file table）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i-node&lt;/code&gt; 表（i-node table）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;文件描述符表每个进程都有一个，打开文件表和 &lt;code&gt;i-node&lt;/code&gt; 表整个系统只有一个，它们三者之间的关系如下图所示。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210930132546.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210930132546.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;对上图的说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在进程&lt;code&gt;A&lt;/code&gt; 中，文件描述符 &lt;code&gt;1&lt;/code&gt; 和&lt;code&gt;20&lt;/code&gt; 都指向了同一个打开文件表项，标号为 &lt;code&gt;23&lt;/code&gt;（指向了打开文件表中下标为 23 的数组元素），这可能是通过调用 &lt;code&gt;dup()&lt;/code&gt;、&lt;code&gt;dup2()&lt;/code&gt;、&lt;code&gt;fcntl()&lt;/code&gt; 或者对同一个文件多次调用了 &lt;code&gt;open()&lt;/code&gt; 函数形成的。&lt;/li&gt;
&lt;li&gt;进程 &lt;code&gt;A&lt;/code&gt; 的文件描述符 &lt;code&gt;2&lt;/code&gt;和进程&lt;code&gt;B&lt;/code&gt; 的文件描述符&lt;code&gt;2&lt;/code&gt; 都指向了同一个文件，这可能是在调用 &lt;code&gt;fork()&lt;/code&gt; 后出现的（即进程 &lt;code&gt;A&lt;/code&gt;、&lt;code&gt;B&lt;/code&gt;是父子进程关系），或者是不同的进程独自去调用&lt;code&gt;open()&lt;/code&gt; 函数打开了同一个文件，此时进程内部的描述符正好分配到与其他进程打开该文件的描述符一样。&lt;/li&gt;
&lt;li&gt;进程 &lt;code&gt;A&lt;/code&gt; 的描述符&lt;code&gt;0&lt;/code&gt;和进程&lt;code&gt;B&lt;/code&gt;的描述符&lt;code&gt;3&lt;/code&gt;分别指向不同的打开文件表项，但这些表项均指向 &lt;code&gt;i-node&lt;/code&gt; 表的同一个条目（标号为 1976）；换言之，它们指向了同一个文件。发生这种情况是因为每个进程各自对同一个文件发起了 &lt;code&gt;open()&lt;/code&gt; 调用。同一个进程两次打开同一个文件，也会发生类似情况。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过文件描述符，可以找到文件指针，从而进入打开文件表。该表存储了以下信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文件偏移量，也就是文件内部指针偏移量。调用&lt;code&gt;read()&lt;/code&gt;或者&lt;code&gt;write()&lt;/code&gt; 函数时，文件偏移量会自动更新，当然也可以使用 &lt;code&gt;lseek()&lt;/code&gt; 直接修改。&lt;/li&gt;
&lt;li&gt;状态标志，比如只读模式、读写模式、追加模式、覆盖模式等。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i-node&lt;/code&gt; 表指针。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然而，要想真正读写文件，还得通过打开文件表的 i-node 指针进入&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;i-node&lt;/code&gt; 表，该表包含了诸如以下的信息：&lt;/li&gt;
&lt;li&gt;文件类型，例如常规文件、套接字或 &lt;code&gt;FIFO&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;文件大小。&lt;/li&gt;
&lt;li&gt;时间戳，比如创建时间、更新时间。&lt;/li&gt;
&lt;li&gt;文件锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;标准文件描述符&#34;&gt;标准文件描述符&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;文件描述符&lt;/th&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;用途&lt;/th&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;POSIX 名称&lt;/th&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;stdio 流&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;0&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;标准输入&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;STDIN FILENO&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;stdin&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;1&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;标准输出&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;STDOUT FILENO&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;stdout&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;2&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;标准错误&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;STDERR FILENO&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;stderr&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;标准文件描述符通常会和重定向符&lt;code&gt;&amp;lt;,&amp;gt;,&amp;lt;&amp;lt;,&amp;gt;&amp;gt;&lt;/code&gt;结合使用。箭头向左表示输入重定向，向右表示输出重定向。文件描述符中的&lt;code&gt;0&lt;/code&gt;通常省略。如&lt;code&gt;0&amp;lt; ~ &amp;lt;&lt;/code&gt;，&lt;code&gt;0&amp;lt;&amp;lt; ~ &amp;lt;&amp;lt;&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;标准输入&#34;&gt;标准输入&lt;/h3&gt;
&lt;p&gt;使用&lt;code&gt;wc&lt;/code&gt;命令统计文档中有多少行字，命令格式如下，详细介绍参考&lt;a href=&#34;https://dunky-z.github.io/2021/07/30/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-wc%E7%BB%9F%E8%AE%A1%E6%96%87%E4%BB%B6%E6%9C%89%E5%A4%9A%E5%B0%91%E5%AD%97%E5%A4%9A%E5%B0%91%E8%A1%8C/&#34;&gt;这篇文章&lt;/a&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wc  [选项]  [文件名]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat test.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is a &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; file.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Hello world!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ wc -l &amp;lt;test.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的重定向符号&lt;code&gt;&amp;lt;&lt;/code&gt;作用就是将&lt;code&gt;test.txt&lt;/code&gt;的内容作为标准输入，传递给&lt;code&gt;wc&lt;/code&gt;命令。&lt;/p&gt;
&lt;h2 id=&#34;标准输出与标准错误&#34;&gt;标准输出与标准错误&lt;/h2&gt;
&lt;p&gt;这个我们每天都在接触，但是可能没有留意。假设我当前目录下只有一个&lt;code&gt;test.txt&lt;/code&gt;文件，执行如下命令&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat text.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is a &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; file.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Hello world!            &lt;span class=&#34;c1&#34;&gt;#标准输出1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat text.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat: test.md: No such file or directory &lt;span class=&#34;c1&#34;&gt;#标准错误2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ls text.txt text.md 1&amp;gt;file.out 2&amp;gt;file.err 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 执行后,没有任何返回值. 原因是, 返回值都重定向到相应的文件中了,而不再前端显示 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat file.out 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;text.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cat file.err 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat: test.md: No such file or directory
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;描述符&#34;&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;描述符&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; 是一个描述符，如果&lt;code&gt;1&lt;/code&gt;或&lt;code&gt;2&lt;/code&gt;前不加&lt;code&gt;&amp;amp;&lt;/code&gt;，会被当成一个普通文件。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1&amp;gt;&amp;amp;2&lt;/code&gt; 意思是把标准输出重定向到标准错误。
&lt;code&gt;2&amp;gt;&amp;amp;1&lt;/code&gt; 意思是把标准错误输出重定向到标准输出。
&lt;code&gt;&amp;amp;&amp;gt;filename&lt;/code&gt; 意思是把标准输出和标准错误输出都重定向到文件 filename 中&lt;/p&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;http://c.biancheng.net/view/942.html&#34;&gt;Linux Shell 重定向（输入输出重定向）精讲&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>Linux 中一切皆文件，比如 C++ 源文件、视频文件、Shell 脚本、可执行文件等，就连键盘、显示器、鼠标等硬件设备也都是文件。</p>
<p>一个 Linux 进程可以打开成百上千个文件，为了表示和区分已经打开的文件，Linux 会给每个文件分配一个编号（一个 ID），这个编号就是一个整数，被称为<strong>文件描述符</strong>（File Descriptor）。</p>
<h2 id="文件描述符是什么">文件描述符是什么？</h2>
<p>一个 Linux 进程启动后，会在内核空间中创建一个 <code>PCB</code> 控制块，<code>PCB</code> 内部有一个<strong>文件描述符表</strong>（File descriptor table），记录着当前进程所有可用的文件描述符，也即当前进程所有打开的文件。</p>
<p>除了文件描述符表，系统还需要维护另外两张表：</p>
<ul>
<li>打开文件表（Open file table）</li>
<li><code>i-node</code> 表（i-node table）</li>
</ul>
<p>文件描述符表每个进程都有一个，打开文件表和 <code>i-node</code> 表整个系统只有一个，它们三者之间的关系如下图所示。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210930132546.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210930132546.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>对上图的说明：</p>
<ul>
<li>在进程<code>A</code> 中，文件描述符 <code>1</code> 和<code>20</code> 都指向了同一个打开文件表项，标号为 <code>23</code>（指向了打开文件表中下标为 23 的数组元素），这可能是通过调用 <code>dup()</code>、<code>dup2()</code>、<code>fcntl()</code> 或者对同一个文件多次调用了 <code>open()</code> 函数形成的。</li>
<li>进程 <code>A</code> 的文件描述符 <code>2</code>和进程<code>B</code> 的文件描述符<code>2</code> 都指向了同一个文件，这可能是在调用 <code>fork()</code> 后出现的（即进程 <code>A</code>、<code>B</code>是父子进程关系），或者是不同的进程独自去调用<code>open()</code> 函数打开了同一个文件，此时进程内部的描述符正好分配到与其他进程打开该文件的描述符一样。</li>
<li>进程 <code>A</code> 的描述符<code>0</code>和进程<code>B</code>的描述符<code>3</code>分别指向不同的打开文件表项，但这些表项均指向 <code>i-node</code> 表的同一个条目（标号为 1976）；换言之，它们指向了同一个文件。发生这种情况是因为每个进程各自对同一个文件发起了 <code>open()</code> 调用。同一个进程两次打开同一个文件，也会发生类似情况。</li>
</ul>
<p>通过文件描述符，可以找到文件指针，从而进入打开文件表。该表存储了以下信息：</p>
<ul>
<li>文件偏移量，也就是文件内部指针偏移量。调用<code>read()</code>或者<code>write()</code> 函数时，文件偏移量会自动更新，当然也可以使用 <code>lseek()</code> 直接修改。</li>
<li>状态标志，比如只读模式、读写模式、追加模式、覆盖模式等。</li>
<li><code>i-node</code> 表指针。</li>
</ul>
<p>然而，要想真正读写文件，还得通过打开文件表的 i-node 指针进入</p>
<ul>
<li><code>i-node</code> 表，该表包含了诸如以下的信息：</li>
<li>文件类型，例如常规文件、套接字或 <code>FIFO</code>。</li>
<li>文件大小。</li>
<li>时间戳，比如创建时间、更新时间。</li>
<li>文件锁。</li>
</ul>
<h2 id="标准文件描述符">标准文件描述符</h2>
<table>
	<thead>
			<tr>
					<th style="text-align: center">文件描述符</th>
					<th style="text-align: center">用途</th>
					<th style="text-align: center">POSIX 名称</th>
					<th style="text-align: center">stdio 流</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: center">0</td>
					<td style="text-align: center">标准输入</td>
					<td style="text-align: center">STDIN FILENO</td>
					<td style="text-align: center">stdin</td>
			</tr>
			<tr>
					<td style="text-align: center">1</td>
					<td style="text-align: center">标准输出</td>
					<td style="text-align: center">STDOUT FILENO</td>
					<td style="text-align: center">stdout</td>
			</tr>
			<tr>
					<td style="text-align: center">2</td>
					<td style="text-align: center">标准错误</td>
					<td style="text-align: center">STDERR FILENO</td>
					<td style="text-align: center">stderr</td>
			</tr>
	</tbody>
</table>
<p>标准文件描述符通常会和重定向符<code>&lt;,&gt;,&lt;&lt;,&gt;&gt;</code>结合使用。箭头向左表示输入重定向，向右表示输出重定向。文件描述符中的<code>0</code>通常省略。如<code>0&lt; ~ &lt;</code>，<code>0&lt;&lt; ~ &lt;&lt;</code>。</p>
<h3 id="标准输入">标准输入</h3>
<p>使用<code>wc</code>命令统计文档中有多少行字，命令格式如下，详细介绍参考<a href="https://dunky-z.github.io/2021/07/30/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-wc%E7%BB%9F%E8%AE%A1%E6%96%87%E4%BB%B6%E6%9C%89%E5%A4%9A%E5%B0%91%E5%AD%97%E5%A4%9A%E5%B0%91%E8%A1%8C/">这篇文章</a>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">wc  [选项]  [文件名]
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ cat test.txt
</span></span><span class="line"><span class="cl">This is a <span class="nb">test</span> file.
</span></span><span class="line"><span class="cl">Hello world!
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ wc -l &lt;test.txt
</span></span><span class="line"><span class="cl"><span class="m">2</span>
</span></span></code></pre></div><p>这里的重定向符号<code>&lt;</code>作用就是将<code>test.txt</code>的内容作为标准输入，传递给<code>wc</code>命令。</p>
<h2 id="标准输出与标准错误">标准输出与标准错误</h2>
<p>这个我们每天都在接触，但是可能没有留意。假设我当前目录下只有一个<code>test.txt</code>文件，执行如下命令</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ cat text.txt
</span></span><span class="line"><span class="cl">This is a <span class="nb">test</span> file.
</span></span><span class="line"><span class="cl">Hello world!            <span class="c1">#标准输出1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ cat text.md
</span></span><span class="line"><span class="cl">cat: test.md: No such file or directory <span class="c1">#标准错误2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ ls text.txt text.md 1&gt;file.out 2&gt;file.err 
</span></span><span class="line"><span class="cl"><span class="c1"># 执行后,没有任何返回值. 原因是, 返回值都重定向到相应的文件中了,而不再前端显示 </span>
</span></span><span class="line"><span class="cl">$ cat file.out 
</span></span><span class="line"><span class="cl">text.txt 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ cat file.err 
</span></span><span class="line"><span class="cl">cat: test.md: No such file or directory
</span></span></code></pre></div><h2 id="描述符"><code>&amp;</code>描述符</h2>
<p><code>&amp;</code> 是一个描述符，如果<code>1</code>或<code>2</code>前不加<code>&amp;</code>，会被当成一个普通文件。</p>
<p><code>1&gt;&amp;2</code> 意思是把标准输出重定向到标准错误。
<code>2&gt;&amp;1</code> 意思是把标准错误输出重定向到标准输出。
<code>&amp;&gt;filename</code> 意思是把标准输出和标准错误输出都重定向到文件 filename 中</p>
<h2 id="参考">参考</h2>
<p><a href="http://c.biancheng.net/view/942.html">Linux Shell 重定向（输入输出重定向）精讲</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>VSCode 中调试带 Makefile 文件的项目</title>
      <link>https://lifeislife.cn/posts/vscode%E4%B8%AD%E8%B0%83%E8%AF%95%E5%B8%A6makefile%E6%96%87%E4%BB%B6%E7%9A%84%E9%A1%B9%E7%9B%AE/</link>
      <pubDate>Mon, 06 Sep 2021 15:41:56 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/vscode%E4%B8%AD%E8%B0%83%E8%AF%95%E5%B8%A6makefile%E6%96%87%E4%BB%B6%E7%9A%84%E9%A1%B9%E7%9B%AE/</guid>
      <description>&lt;p&gt;在调试 QEMU 时，自己需要修改源文件，但是每次修改都需要在命令行重新&lt;code&gt;make&lt;/code&gt;编译一遍，比较麻烦，想到之前刚刚配置过&lt;code&gt;tasks.json&lt;/code&gt;文件，可以把命令行任务配置到文件里，&lt;code&gt;make&lt;/code&gt;命令不也一样可以加入吗？修改&lt;code&gt;tasks.json&lt;/code&gt;文件如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2.0.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;tasks&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;c1&#34;&gt;//任务的名字方便执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;label&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;make qemu&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;make&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;c1&#34;&gt;//8 线程编译
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;s2&#34;&gt;&amp;#34;-j8&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;options&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;//切换到 build 文件夹下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;cwd&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}/build&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 启动 qemu 供调试器连接
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;shell&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;label&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Run Qemu Server(RISCV)&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;//在执行这个任务前，先执行 make qemu 任务、
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;//这样就可以在执行调试时，自动先编译一遍
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;dependsOn&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;make qemu&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;qemu-system-riscv64&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;-g&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>在调试 QEMU 时，自己需要修改源文件，但是每次修改都需要在命令行重新<code>make</code>编译一遍，比较麻烦，想到之前刚刚配置过<code>tasks.json</code>文件，可以把命令行任务配置到文件里，<code>make</code>命令不也一样可以加入吗？修改<code>tasks.json</code>文件如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;version&#34;</span><span class="p">:</span> <span class="s2">&#34;2.0.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;tasks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">       <span class="c1">//任务的名字方便执行
</span></span></span><span class="line"><span class="cl">      <span class="nt">&#34;label&#34;</span><span class="p">:</span> <span class="s2">&#34;make qemu&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;shell&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;make&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:[</span>
</span></span><span class="line"><span class="cl">          <span class="c1">//8 线程编译
</span></span></span><span class="line"><span class="cl">          <span class="s2">&#34;-j8&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;options&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">//切换到 build 文件夹下
</span></span></span><span class="line"><span class="cl">        <span class="nt">&#34;cwd&#34;</span><span class="p">:</span> <span class="s2">&#34;${workspaceFolder}/build&#34;</span> 
</span></span><span class="line"><span class="cl">      <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 启动 qemu 供调试器连接
</span></span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;shell&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;label&#34;</span><span class="p">:</span> <span class="s2">&#34;Run Qemu Server(RISCV)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="c1">//在执行这个任务前，先执行 make qemu 任务、
</span></span></span><span class="line"><span class="cl">        <span class="c1">//这样就可以在执行调试时，自动先编译一遍
</span></span></span><span class="line"><span class="cl">        <span class="nt">&#34;dependsOn&#34;</span><span class="p">:</span> <span class="s2">&#34;make qemu&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;qemu-system-riscv64&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;-g&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>解决 gcc-multilib : 依赖：gcc-4.8-multilib (&gt;= 4.8.2-5~) 但是它将不会被安装</title>
      <link>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3gcc-multilib-%E4%BE%9D%E8%B5%96-gcc-4-8-multilib-4-8-2-5-%E4%BD%86%E6%98%AF%E5%AE%83%E5%B0%86%E4%B8%8D%E4%BC%9A%E8%A2%AB%E5%AE%89%E8%A3%85/</link>
      <pubDate>Fri, 03 Sep 2021 10:44:44 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3gcc-multilib-%E4%BE%9D%E8%B5%96-gcc-4-8-multilib-4-8-2-5-%E4%BD%86%E6%98%AF%E5%AE%83%E5%B0%86%E4%B8%8D%E4%BC%9A%E8%A2%AB%E5%AE%89%E8%A3%85/</guid>
      <description>&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;
&lt;p&gt;这是一类问题，不仅限于安装 gcc，这类问题的根本原因在于，&lt;strong&gt;Ubuntu 已安装的软件包版本高，而所安装软件的依赖包版本低&lt;/strong&gt;，这样在安装高版软件时，已有的软件包依赖你要安装的软件包，你把软件包升级了，可能就会破坏这个依赖关系，所以&lt;code&gt;apt-get&lt;/code&gt;不让你安装。&lt;/p&gt;
&lt;p&gt;这时就要请到大杀器-&lt;code&gt;aptitude&lt;/code&gt;，它与 &lt;code&gt;apt-get&lt;/code&gt;一样，是 Debian 及其衍生系统中功能极其强大的包管理工具。与 &lt;code&gt;apt-get&lt;/code&gt; 不同的是，&lt;code&gt;aptitude&lt;/code&gt;在处理依赖问题上更佳一些。举例来说，&lt;code&gt;aptitude&lt;/code&gt;在删除一个包时，会同时删除本身所依赖的包。这样，系统中不会残留无用的包，整个系统更为干净。&lt;/p&gt;
&lt;h2 id=&#34;方法&#34;&gt;方法&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$sudo apt-get install aptitude  //安装aptitude包管理器
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$sudo aptitude install gcc-multilib //用新的包管理器安装你要安装的软件
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装&lt;code&gt;gcc-multilib&lt;/code&gt;时会把所有依赖包一并安装，此时会让你同意，选择&lt;code&gt;n&lt;/code&gt;就行。&lt;/p&gt;
&lt;p&gt;接下来就会解决已经安装的包之间的依赖关系，他会降级或升级一些软件包来匹配当前安装的软件版本，此时选择&lt;code&gt;y&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;完成以上操作，再次正常安装需要的软件包即可成功安装。&lt;/p&gt;
&lt;p&gt;如果无法正常安装，重复以上操作，每次都选择&lt;code&gt;n&lt;/code&gt;。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="问题">问题</h2>
<p>这是一类问题，不仅限于安装 gcc，这类问题的根本原因在于，<strong>Ubuntu 已安装的软件包版本高，而所安装软件的依赖包版本低</strong>，这样在安装高版软件时，已有的软件包依赖你要安装的软件包，你把软件包升级了，可能就会破坏这个依赖关系，所以<code>apt-get</code>不让你安装。</p>
<p>这时就要请到大杀器-<code>aptitude</code>，它与 <code>apt-get</code>一样，是 Debian 及其衍生系统中功能极其强大的包管理工具。与 <code>apt-get</code> 不同的是，<code>aptitude</code>在处理依赖问题上更佳一些。举例来说，<code>aptitude</code>在删除一个包时，会同时删除本身所依赖的包。这样，系统中不会残留无用的包，整个系统更为干净。</p>
<h2 id="方法">方法</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$sudo apt-get install aptitude  //安装aptitude包管理器
</span></span><span class="line"><span class="cl">$sudo aptitude install gcc-multilib //用新的包管理器安装你要安装的软件
</span></span></code></pre></div><p>安装<code>gcc-multilib</code>时会把所有依赖包一并安装，此时会让你同意，选择<code>n</code>就行。</p>
<p>接下来就会解决已经安装的包之间的依赖关系，他会降级或升级一些软件包来匹配当前安装的软件版本，此时选择<code>y</code>。</p>
<p>完成以上操作，再次正常安装需要的软件包即可成功安装。</p>
<p>如果无法正常安装，重复以上操作，每次都选择<code>n</code>。</p>
]]></content:encoded>
    </item>
    <item>
      <title>解决 fatal error: bits/libc-header-start.h：no such file</title>
      <link>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3fatal-error-bits-libc-header-start-hno-such-file/</link>
      <pubDate>Fri, 03 Sep 2021 09:26:34 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3fatal-error-bits-libc-header-start-hno-such-file/</guid>
      <description>&lt;h2 id=&#34;保留现场&#34;&gt;保留现场&lt;/h2&gt;
&lt;p&gt;想要分别编译 32 位和 64 位的程序时，gcc 出现了错误，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;In file included from func_call.c:1:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: 没有那个文件或目录
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   27 | #include &amp;lt;bits/libc-header-start.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;compilation terminated.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;问题解决&#34;&gt;问题解决&lt;/h2&gt;
&lt;p&gt;问题原因猜测是默认 gcc 只提供当前机器的版本，解决如下&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt install gcc-multilib
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="保留现场">保留现场</h2>
<p>想要分别编译 32 位和 64 位的程序时，gcc 出现了错误，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">In file included from func_call.c:1:
</span></span><span class="line"><span class="cl">/usr/include/stdio.h:27:10: fatal error: bits/libc-header-start.h: 没有那个文件或目录
</span></span><span class="line"><span class="cl">   27 | #include &lt;bits/libc-header-start.h&gt;
</span></span><span class="line"><span class="cl">      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~
</span></span><span class="line"><span class="cl">compilation terminated.
</span></span></code></pre></div><h2 id="问题解决">问题解决</h2>
<p>问题原因猜测是默认 gcc 只提供当前机器的版本，解决如下</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt install gcc-multilib
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>QEMU 源码分析-虚拟 CPU 创建</title>
      <link>https://lifeislife.cn/posts/qemu%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E8%99%9A%E6%8B%9Fcpu%E5%88%9B%E5%BB%BA/</link>
      <pubDate>Wed, 01 Sep 2021 18:22:14 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E8%99%9A%E6%8B%9Fcpu%E5%88%9B%E5%BB%BA/</guid>
      <description>&lt;h2 id=&#34;流程图&#34;&gt;流程图&lt;/h2&gt;
&lt;p&gt;先开个头吧，把创建流程稍微捋一下，找到创建虚拟 CPU 的模块。至于中间的流程还没有详细分析，万事开头难，先上手再说吧。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210901182329.svg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210901182329.svg&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;qemu_add_opts解析-qemu-的命令行&#34;&gt;&lt;code&gt;qemu_add_opts&lt;/code&gt;解析 qemu 的命令行&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;qemu_init&lt;/code&gt;函数中下面这一长串内容，就是在解析命令行的参数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;drive&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;drive&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Legacy&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;drive&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;drive&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;common&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;drive&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;drive&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;drive&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;drive&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sbdry&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;runtime&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;chardev&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;device&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;netdev&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nic&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sqemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;net&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rtc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;global_opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mon&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sqemu&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为什么有这么多的 &lt;code&gt;opts&lt;/code&gt;呢？这是因为，实际运行中创建的&lt;code&gt;kvm&lt;/code&gt;参数会复杂&lt;code&gt;N&lt;/code&gt;倍。这里我们贴一个开源云平台软件 &lt;code&gt;OpenStack&lt;/code&gt; 创建出来的&lt;code&gt;KVM&lt;/code&gt;的参数，如下所示。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-x86_64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-enable-kvm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-name instance-00000024
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-machine pc-i440fx-trusty,accel&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;kvm,usb&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;off
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-cpu SandyBridge,+erms,+smep,+fsgsbase,+pdpe1gb,+rdrand,+f16c,+osxsave,+dca,+pcid,+pdcm,+xtpr,+tm2,+est,+smx,+vmx,+ds_cpl,+monitor,+dtes64,+pbe,+tm,+ht,+ss,+acpi,+ds,+vme
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-m &lt;span class=&#34;m&#34;&gt;2048&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-smp 1,sockets&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1,cores&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1,threads&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rtc &lt;span class=&#34;nv&#34;&gt;base&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;utc,driftfix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;slew
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-drive &lt;span class=&#34;nv&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/var/lib/nova/instances/1f8e6f7e-5a70-4780-89c1-464dc0e7f308/disk,if&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;none,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;drive-virtio-disk0,format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;qcow2,cache&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;none
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device virtio-blk-pci,scsi&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;off,bus&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;pci.0,addr&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x4,drive&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;drive-virtio-disk0,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;virtio-disk0,bootindex&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-netdev tap,fd&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;32,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hostnet0,vhost&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;on,vhostfd&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;37&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device virtio-net-pci,netdev&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;hostnet0,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;net0,mac&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;fa:16:3e:d1:2d:99,bus&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;pci.0,addr&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-chardev file,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;charserial0,path&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/var/lib/nova/instances/1f8e6f7e-5a70-4780-89c1-464dc0e7f308/console.log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-vnc 0.0.0.0:12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-device cirrus-vga,id&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;video0,bus&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;pci.0,addr&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0x2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-enable-kvm&lt;/code&gt;：表示启用硬件辅助虚拟化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-name instance-00000024&lt;/code&gt;：表示虚拟机的名称。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-machine pc-i440fx-trusty,accel=kvm,usb=off&lt;/code&gt;：machine 是什么呢？其实就是计算机体系结构。不知道什么是体系结构的话，可以订阅极客时间的另一个专栏《深入浅出计算机组成原理》。
qemu 会模拟多种体系结构，常用的有普通 PC 机，也即 x86 的 32 位或者 64 位的体系结构、Mac 电脑 PowerPC 的体系结构、Sun 的体系结构、MIPS 的体系结构，精简指令集。如果使用 KVM hardware-assisted virtualization，也即 BIOS 中 VD-T 是打开的，则参数中 &lt;code&gt;accel=kvm&lt;/code&gt;。如果不使用 &lt;code&gt;hardware-assisted virtualization&lt;/code&gt;，用的是纯模拟，则有参数 &lt;code&gt;accel = tcg&lt;/code&gt;，&lt;code&gt;-no-kvm&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-cpu SandyBridge,+erms,+smep,+fsgsbase,+pdpe1gb,+rdrand,+f16c,+osxsave,+dca,+pcid,+pdcm,+xtpr,+tm2,+est,+smx,+vmx,+ds_cpl,+monitor,+dtes64,+pbe,+tm,+ht,+ss,+acpi,+ds,+vme&lt;/code&gt;：表示设置 CPU，SandyBridge 是 Intel 处理器，后面的加号都是添加的 CPU 的参数，这些参数会显示在 /proc/cpuinfo 里面。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-m 2048&lt;/code&gt;：表示内存。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-smp 1,sockets=1,cores=1,threads=1&lt;/code&gt;：&lt;code&gt;SMP&lt;/code&gt; 我们解析过，叫对称多处理器，和&lt;code&gt;NUMA&lt;/code&gt; 对应。qemu 仿真了一个具有 1 个 &lt;code&gt;vcpu&lt;/code&gt;，一个 &lt;code&gt;socket&lt;/code&gt;，一个 &lt;code&gt;core&lt;/code&gt;，一个 &lt;code&gt;threads&lt;/code&gt; 的处理器。
&lt;code&gt;socket&lt;/code&gt;、&lt;code&gt;core&lt;/code&gt;、&lt;code&gt;threads&lt;/code&gt; 是什么概念呢？&lt;code&gt;socket&lt;/code&gt; 就是主板上插 CPU 的槽的数目，也即常说的“路”，&lt;code&gt;core&lt;/code&gt; 就是我们平时说的“核”，即双核、4 核等。&lt;code&gt;thread&lt;/code&gt; 就是每个 core 的硬件线程数，即超线程。举个具体的例子，某个服务器是：2 路 4 核超线程（一般默认为 2 个线程），通过 &lt;code&gt;cat /proc/cpuinfo&lt;/code&gt;，我们看到的是 242=16 个&lt;code&gt;processor&lt;/code&gt;，很多人也习惯成为 16 核了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-rtc base=utc,driftfix=slew&lt;/code&gt;：表示系统时间由参数 &lt;code&gt;-rtc&lt;/code&gt; 指定。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-device cirrus-vga,id=video0,bus=pci.0,addr=0x2&lt;/code&gt;：表示显示器用参数 &lt;code&gt;-vga&lt;/code&gt; 设置，默认为 &lt;code&gt;cirrus&lt;/code&gt;，它模拟了 &lt;code&gt;CL-GD5446PCI VGA card&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有关网卡，使用 &lt;code&gt;-net&lt;/code&gt; 参数和 &lt;code&gt;-device&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从 HOST 角度：&lt;code&gt;-netdev tap,fd=32,id=hostnet0,vhost=on,vhostfd=37&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从 GUEST 角度：&lt;code&gt;-device virtio-net-pci,netdev=hostnet0,id=net0,mac=fa:16:3e:d1:2d:99,bus=pci.0,addr=0x3&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有关硬盘，使用 &lt;code&gt;-hda -hdb&lt;/code&gt;，或者使用 &lt;code&gt;-drive&lt;/code&gt; 和 &lt;code&gt;-device&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从 HOST 角度：&lt;code&gt;-drive file=/var/lib/nova/instances/1f8e6f7e-5a70-4780-89c1-464dc0e7f308/disk,if=none,id=drive-virtio-disk0,format=qcow2,cache=none&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从 GUEST 角度：&lt;code&gt;-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-vnc 0.0.0.0:12&lt;/code&gt;：设置 VNC。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;module_call_init初始化所有模块&#34;&gt;&lt;code&gt;module_call_init&lt;/code&gt;初始化所有模块&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_init_subsystems&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;module_call_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当虚拟机真的要使用物理资源的时候，对下面的物理机上的资源要进行请求，所以它的工作模式有点儿类似操作系统对接驱动。驱动要符合一定的格式，才能算操作系统的一个模块。同理，qemu 为了模拟各种各样的设备，也需要管理各种各样的模块，这些模块也需要符合一定的格式。&lt;/p&gt;
&lt;p&gt;定义一个 qemu 模块会调用 &lt;code&gt;type_init&lt;/code&gt;。例如，&lt;code&gt;kvm&lt;/code&gt; 的模块要在 &lt;code&gt;accel/kvm/kvm-all.c&lt;/code&gt; 文件里面实现。在这个文件里面，有一行下面的代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_accel_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_KVM_ACCEL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_ACCEL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_accel_instance_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_accel_class_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KVMState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_type_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;type_register_static&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kvm_accel_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;type_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kvm_type_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;找到&lt;code&gt;type_init&lt;/code&gt;的定义&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define type_init(function) module_init(function, MODULE_INIT_QOM)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从代码里面的定义我们可以看出来，&lt;code&gt;type_init&lt;/code&gt; 后面的参数是一个函数，调用 &lt;code&gt;type_init&lt;/code&gt; 就相当于调用 &lt;code&gt;module_init&lt;/code&gt;，在这里函数就是 &lt;code&gt;kvm_type_init&lt;/code&gt;，类型就是 &lt;code&gt;MODULE_INIT_QOM&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;再查看一下&lt;code&gt;module_init&lt;/code&gt;的定义&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//include/qemu/module.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define module_init(function, type)                                         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;{                                                                           \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    register_module_init(function, type);                                   \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;module_init&lt;/code&gt; 最终要调用 &lt;code&gt;register_module_init&lt;/code&gt;。属于 &lt;code&gt;MODULE_INIT_QOM&lt;/code&gt; 这种类型的，有一个 &lt;code&gt;Module&lt;/code&gt; 列表 &lt;code&gt;ModuleTypeList&lt;/code&gt;，列表里面是一项一项的 &lt;code&gt;ModuleEntry&lt;/code&gt;。&lt;code&gt;KVM&lt;/code&gt; 就是其中一项，并且会初始化每一项的 &lt;code&gt;init&lt;/code&gt; 函数为参数表示的函数 &lt;code&gt;fn&lt;/code&gt;，也即 &lt;code&gt;KVM&lt;/code&gt; 这个 &lt;code&gt;module&lt;/code&gt; 的 &lt;code&gt;init&lt;/code&gt; 函数就是 &lt;code&gt;kvm_type_init&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;当然，&lt;code&gt;MODULE_INIT_QOM&lt;/code&gt; 这种类型会有很多很多的 &lt;code&gt;module&lt;/code&gt;，从后面的代码我们可以看到，所有调用 &lt;code&gt;type_init&lt;/code&gt; 的地方都注册了一个 &lt;code&gt;MODULE_INIT_QOM&lt;/code&gt; 类型的 &lt;code&gt;Module&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;了解了 &lt;code&gt;Module&lt;/code&gt; 的注册机制，我们继续回到 &lt;code&gt;qemu_init_subsystems&lt;/code&gt; 函数中 &lt;code&gt;module_call_init&lt;/code&gt; 的调用。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_init_subsystems&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Error&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;os_set_line_buffering&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;module_call_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MODULE_INIT_TRACE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;qemu_init_cpu_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;qemu_init_cpu_loop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;qemu_mutex_lock_iothread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;atexit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu_run_exit_notifiers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;module_call_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MODULE_INIT_QOM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;module_call_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MODULE_INIT_MIGRATION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// utils/module.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;module_call_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_init_type&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ModuleTypeList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ModuleEntry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;l&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;find_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;QTAILQ_FOREACH&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;module_call_init&lt;/code&gt; 中，我们会找到 &lt;code&gt;MODULE_INIT_QOM&lt;/code&gt; 这种类型对应的 &lt;code&gt;ModuleTypeList&lt;/code&gt;，找出列表中所有的 &lt;code&gt;ModuleEntry&lt;/code&gt;，然后调用每个 &lt;code&gt;ModuleEntry&lt;/code&gt; 的 &lt;code&gt;init&lt;/code&gt; 函数。这里需要注意的是，在 &lt;code&gt;module_call_init&lt;/code&gt; 调用的这一步，所有 &lt;code&gt;Module&lt;/code&gt; 的 &lt;code&gt;init&lt;/code&gt; 函数都已经被调用过了。&lt;/p&gt;
&lt;p&gt;后面我们会看到很多的 &lt;code&gt;Module&lt;/code&gt;，当我们后面再次遇到时，需要意识到，它的 &lt;code&gt;init&lt;/code&gt; 函数在这里也被调用过了。这里我们还是以对于 &lt;code&gt;kvm&lt;/code&gt; 这个 &lt;code&gt;module&lt;/code&gt; 为例子，看看它的 &lt;code&gt;init&lt;/code&gt; 函数都做了哪些事情。我们会发现，其实它调用的是 &lt;code&gt;kvm_type_init&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;kvm_type_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;type_register_static&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kvm_accel_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;TypeImpl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;type_register_static&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;type_register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;TypeImpl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;type_register&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;type_register_internal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeImpl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;type_register_internal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;TypeImpl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;type_new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;type_table_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeImpl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;type_new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;TypeImpl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;type_table_lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_strdup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_strdup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_base_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_base_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_data&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_post_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_post_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_finalize&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_finalize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;abstract&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;abstract&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interfaces&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interfaces&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interfaces&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;typename&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_strdup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;interfaces&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num_interfaces&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;type_table_add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TypeImpl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enumerating_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;g_hash_table_insert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;type_table_get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GHashTable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;type_table_get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GHashTable&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type_table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type_table&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;type_table&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_hash_table_new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g_str_hash&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;g_str_equal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type_table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TypeInfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_accel_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_KVM_ACCEL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TYPE_ACCEL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kvm_accel_class_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;KVMState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;调用流程如下：虚线表示返回&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210907133931.svg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210907133931.svg&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;每一个 &lt;code&gt;Module&lt;/code&gt; 既然要模拟某种设备，那应该定义一种类型 &lt;code&gt;TypeImpl&lt;/code&gt; 来表示这些设备，这其实是一种&lt;code&gt;面向对象编程&lt;/code&gt;的思路，只不过这里用的是纯 C 语言的实现，所以需要变相实现一下类和对象。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kvm_type_init&lt;/code&gt; 会注册 &lt;code&gt;kvm_accel_type&lt;/code&gt;，定义上面的代码，我们可以认为这样动态定义了一个类。这个类的名字是 &lt;code&gt;TYPE_KVM_ACCEL&lt;/code&gt;，这个类有父类 &lt;code&gt;TYPE_ACCEL&lt;/code&gt;，这个类的初始化应该调用函数 &lt;code&gt;kvm_accel_class_init&lt;/code&gt;。如果用这个类声明一个对象，对象的大小应该是 &lt;code&gt;instance_size&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;type_register_internal&lt;/code&gt; 中，我们会根据 &lt;code&gt;kvm_accel_type&lt;/code&gt; 这个 &lt;code&gt;TypeInfo&lt;/code&gt;，创建一个&lt;code&gt;TypeImpl&lt;/code&gt; 来表示这个新注册的类，也就是说，&lt;code&gt;TypeImpl&lt;/code&gt; 才是我们想要声明的那个 &lt;code&gt;class&lt;/code&gt;。在 qemu 里面，有一个全局的哈希表 &lt;code&gt;type_table&lt;/code&gt;，用来存放所有定义的类。在 &lt;code&gt;type_new&lt;/code&gt; 里面，我们先从全局表里面根据名字&lt;code&gt;type_table_lookup&lt;/code&gt;查找找这个类。如果找到，说明这个类曾经被注册过，就报错；如果没有找到，说明这是一个新的类，则将 &lt;code&gt;TypeInfo&lt;/code&gt; 里面信息填到 &lt;code&gt;TypeImpl&lt;/code&gt; 里面。&lt;code&gt;type_table_add&lt;/code&gt; 会将这个类注册到全局的表里面。到这里，我们注意，&lt;code&gt;class_init&lt;/code&gt; 还没有被调用，也即这个类现在还处于纸面的状态。&lt;/p&gt;
&lt;p&gt;这点更加像 Java 的反射机制了。在 Java 里面，对于一个类，首先我们写代码的时候要写一个 &lt;code&gt;class xxx&lt;/code&gt; 的定义，编译好就放在&lt;code&gt;.class&lt;/code&gt; 文件中，这也是出于纸面的状态。然后，Java 会有一个 &lt;code&gt;Class&lt;/code&gt; 对象，用于读取和表示这个纸面上的 &lt;code&gt;class xxx&lt;/code&gt;，可以生成真正的对象。&lt;/p&gt;
&lt;p&gt;相同的过程在后面的代码中我们也可以看到，&lt;code&gt;class_init&lt;/code&gt; 会生成&lt;code&gt;XXXClass&lt;/code&gt;，就相当于 Java 里面的 &lt;code&gt;Class&lt;/code&gt;对象，&lt;code&gt;TypeImpl&lt;/code&gt; 还会有一个 &lt;code&gt;instance_init&lt;/code&gt; 函数，相当于构造函数，用于根据 &lt;code&gt;XXXClass&lt;/code&gt; 生成 &lt;code&gt;Object&lt;/code&gt;，这就相当于 Java 反射里面最终创建的对象。和构造函数对应的还有 &lt;code&gt;instance_finalize&lt;/code&gt;，相当于析构函数。&lt;/p&gt;
&lt;p&gt;这一套反射机制放在 &lt;code&gt;qom&lt;/code&gt; 文件夹下面，全称 &lt;code&gt;QEMU Object Model&lt;/code&gt;，也即用 C 实现了一套&lt;strong&gt;面向对象的反射机制&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;初始化-machine&#34;&gt;初始化 machine&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210913115046.svg&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210913115046.svg&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//vl.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;qemu_create_machine&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;select_machine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在创建 machine 之前，先要通过&lt;code&gt;select_machine&lt;/code&gt;确定一个&lt;code&gt;machine&lt;/code&gt;。&lt;code&gt;select_machine&lt;/code&gt;又是怎么确定的呢，这就和我们命令行的输入有关，比如我们&lt;code&gt;-m spike&lt;/code&gt;，那么这里就会选择&lt;code&gt;spike&lt;/code&gt;作为&lt;code&gt;machine&lt;/code&gt;。它的定义在&lt;code&gt;hw/riscv/spike.c&lt;/code&gt;中。&lt;/p&gt;
&lt;p&gt;在源码最后有这么一句，会和我们上面解析的&lt;code&gt;type_init&lt;/code&gt; 是一样的，在全局的表里面注册了一个全局的名字是&lt;code&gt;spike&lt;/code&gt;的纸面上的 &lt;code&gt;class&lt;/code&gt;，也即 &lt;code&gt;TypeImpl&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;type_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;spike_machine_init_reqister_types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在全局表中有这个纸面上的 &lt;code&gt;class&lt;/code&gt; 了。我们回到 &lt;code&gt;select_machine&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;select_machine&lt;/code&gt; 中，有两种方式可以生成 &lt;code&gt;MachineClass&lt;/code&gt;。一种方式是 &lt;code&gt;find_default_machine&lt;/code&gt;，找一个默认的；另一种方式是 &lt;code&gt;machine_parse&lt;/code&gt;，通过解析参数生成 &lt;code&gt;MachineClass&lt;/code&gt;。无论哪种方式，都会调用 &lt;code&gt;object_class_get_list&lt;/code&gt; 获得一个 &lt;code&gt;MachineClass&lt;/code&gt; 的列表，然后在里面找。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;select_machine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;GSList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;object_class_get_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TYPE_MACHINE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machine_class&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;find_default_machine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;QemuOpts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Location&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;loc_push_none&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_get_machine_opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;qemu_opts_loc_restore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;qemu_opt_get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;machine_class&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;machine_parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;optarg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machine_class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;error_report&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;No machine specified, and there is no default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;error_printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Use -machine help to list supported machines&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;loc_pop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;g_slist_free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;machine_class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;find_default_machine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GSList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;GSList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;el&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default_machineclass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;el&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;el&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;el&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;el&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;el&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;assert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default_machineclass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Multiple default machines&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;default_machineclass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;default_machineclass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;machine_parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GSList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;GSList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;el&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;is_help_option&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Supported machines are:&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_slist_sort&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;machine_class_cmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;el&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;el&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;el&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;el&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;MachineClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;el&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alias&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%-20s %s (alias of %s)&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alias&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;desc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%-20s %s%s%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;desc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_default&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34; (default)&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;deprecation_reason&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34; (deprecated)&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;find_machine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;machines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;error_report&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;unsupported machine type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;error_printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Use -machine help to list supported machines&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;object_class_get_list&lt;/code&gt; 定义如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;GSList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;object_class_get_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;implements_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;include_abstract&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;GSList&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;list&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;object_class_foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;object_class_get_list_tramp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                         &lt;span class=&#34;n&#34;&gt;implements_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;include_abstract&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;object_class_foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ObjectClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;klass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opaque&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                          &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;implements_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;include_abstract&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                          &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opaque&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;OCFData&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;implements_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;include_abstract&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opaque&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;enumerating_types&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;g_hash_table_foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;type_table_get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;object_class_foreach_tramp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;enumerating_types&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在全局表 &lt;code&gt;type_table_get()&lt;/code&gt; 中，对于每一项 &lt;code&gt;TypeImpl&lt;/code&gt;，我们都执行 &lt;code&gt;object_class_foreach_tramp&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;object_class_foreach_tramp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gpointer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gpointer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                       &lt;span class=&#34;n&#34;&gt;gpointer&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opaque&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;OCFData&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;opaque&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;TypeImpl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ObjectClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;k&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;type_initialize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;k&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;include_abstract&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;abstract&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;implements_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;object_class_dynamic_cast&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;k&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;implements_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;k&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opaque&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;object_class_foreach_tramp&lt;/code&gt; 中，会调用将 &lt;code&gt;type_initialize&lt;/code&gt;，这里面会调用 &lt;code&gt;class_init&lt;/code&gt; 将纸面上的 &lt;code&gt;class&lt;/code&gt; 也即 &lt;code&gt;TypeImpl&lt;/code&gt; 变为 &lt;code&gt;ObjectClass&lt;/code&gt;，&lt;code&gt;ObjectClass&lt;/code&gt; 是所有&lt;code&gt;Class&lt;/code&gt; 类的祖先，&lt;code&gt;MachineClass&lt;/code&gt; 是它的子类。&lt;/p&gt;
&lt;p&gt;因为在 &lt;code&gt;machine&lt;/code&gt; 的命令行里面，我们指定了名字为&lt;code&gt;spike&lt;/code&gt;，就肯定能够找到我们注册过了的 &lt;code&gt;TypeImpl&lt;/code&gt;，并调用它的 &lt;code&gt;class_init&lt;/code&gt; 函数。&lt;/p&gt;
&lt;p&gt;所以，当 &lt;code&gt;select_machine&lt;/code&gt; 执行完毕后，就有一个 &lt;code&gt;MachineClass&lt;/code&gt; 了。&lt;/p&gt;
&lt;p&gt;接着，我们回到 &lt;code&gt;qemu_create_machine&lt;/code&gt; 中的&lt;code&gt;object_new_with_class&lt;/code&gt;。这就很好理解了，&lt;code&gt;MachineClass&lt;/code&gt; 是一个 &lt;code&gt;Class&lt;/code&gt; 类，接下来应该通过它生成一个 &lt;code&gt;Instance&lt;/code&gt;，也即对象，这就是 &lt;code&gt;object_new_with_class&lt;/code&gt; 的作用。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;object_new_with_class&lt;/code&gt; 中，&lt;code&gt;TypeImpl&lt;/code&gt; 的 &lt;code&gt;instance_init&lt;/code&gt; 会被调用，创建一个对象。&lt;code&gt;current_machine&lt;/code&gt; 就是这个对象，它的类型是&lt;code&gt;MachineState&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;object_new_with_class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ObjectClass&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;klass&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;object_new_with_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;klass&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;object_new_with_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Type&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;type_initialize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;g_malloc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;object_initialize_with_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instance_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;free&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;g_free&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;至此，绕了这么大一圈，有关体系结构的对象才创建完毕，接下来很多的设备的初始化，包括 CPU 和内存的初始化，都是围绕着体系结构的对象来的，后面我们会常常看到&lt;code&gt;current_machine&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220308180036.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220308180036.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://www.cnblogs.com/nm90/p/15661202.html&#34;&gt;Qemu CPU 虚拟化 - 人生一世，草木一秋。 - 博客园&lt;/a&gt;
&lt;a href=&#34;https://www.cnblogs.com/LoyenWang/p/13796537.html&#34;&gt;【原创】Linux 虚拟化 KVM-Qemu 分析（四）之 CPU 虚拟化（2） - LoyenWang - 博客园&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="流程图">流程图</h2>
<p>先开个头吧，把创建流程稍微捋一下，找到创建虚拟 CPU 的模块。至于中间的流程还没有详细分析，万事开头难，先上手再说吧。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210901182329.svg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210901182329.svg" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="qemu_add_opts解析-qemu-的命令行"><code>qemu_add_opts</code>解析 qemu 的命令行</h2>
<p><code>qemu_init</code>函数中下面这一长串内容，就是在解析命令行的参数。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">drive</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="n">drive</span> <span class="nf">opts</span><span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">Legacy</span> <span class="n">drive</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="n">drive</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">common</span> <span class="n">drive</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="n">drive</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">drive</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="n">drive</span> <span class="nf">opts</span> <span class="p">(</span><span class="n">sbdry</span> <span class="n">runtime</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="n">qemu</span> <span class="n">chardev</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">device</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">netdev</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">nic</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="n">sqemu</span> <span class="n">net</span> <span class="n">opts</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">rtc</span> <span class="n">opts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">global_opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">qemu</span> <span class="n">mon</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">qemu</span> <span class="n">add</span> <span class="nf">opts</span> <span class="p">(</span><span class="n">sqemu</span> <span class="n">trace</span> <span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span>
</span></span></code></pre></div><p>为什么有这么多的 <code>opts</code>呢？这是因为，实际运行中创建的<code>kvm</code>参数会复杂<code>N</code>倍。这里我们贴一个开源云平台软件 <code>OpenStack</code> 创建出来的<code>KVM</code>的参数，如下所示。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">qemu-system-x86_64
</span></span><span class="line"><span class="cl">-enable-kvm
</span></span><span class="line"><span class="cl">-name instance-00000024
</span></span><span class="line"><span class="cl">-machine pc-i440fx-trusty,accel<span class="o">=</span>kvm,usb<span class="o">=</span>off
</span></span><span class="line"><span class="cl">-cpu SandyBridge,+erms,+smep,+fsgsbase,+pdpe1gb,+rdrand,+f16c,+osxsave,+dca,+pcid,+pdcm,+xtpr,+tm2,+est,+smx,+vmx,+ds_cpl,+monitor,+dtes64,+pbe,+tm,+ht,+ss,+acpi,+ds,+vme
</span></span><span class="line"><span class="cl">-m <span class="m">2048</span>
</span></span><span class="line"><span class="cl">-smp 1,sockets<span class="o">=</span>1,cores<span class="o">=</span>1,threads<span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">......
</span></span><span class="line"><span class="cl">-rtc <span class="nv">base</span><span class="o">=</span>utc,driftfix<span class="o">=</span>slew
</span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span>/var/lib/nova/instances/1f8e6f7e-5a70-4780-89c1-464dc0e7f308/disk,if<span class="o">=</span>none,id<span class="o">=</span>drive-virtio-disk0,format<span class="o">=</span>qcow2,cache<span class="o">=</span>none
</span></span><span class="line"><span class="cl">-device virtio-blk-pci,scsi<span class="o">=</span>off,bus<span class="o">=</span>pci.0,addr<span class="o">=</span>0x4,drive<span class="o">=</span>drive-virtio-disk0,id<span class="o">=</span>virtio-disk0,bootindex<span class="o">=</span><span class="m">1</span>
</span></span><span class="line"><span class="cl">-netdev tap,fd<span class="o">=</span>32,id<span class="o">=</span>hostnet0,vhost<span class="o">=</span>on,vhostfd<span class="o">=</span><span class="m">37</span>
</span></span><span class="line"><span class="cl">-device virtio-net-pci,netdev<span class="o">=</span>hostnet0,id<span class="o">=</span>net0,mac<span class="o">=</span>fa:16:3e:d1:2d:99,bus<span class="o">=</span>pci.0,addr<span class="o">=</span>0x3
</span></span><span class="line"><span class="cl">-chardev file,id<span class="o">=</span>charserial0,path<span class="o">=</span>/var/lib/nova/instances/1f8e6f7e-5a70-4780-89c1-464dc0e7f308/console.log
</span></span><span class="line"><span class="cl">-vnc 0.0.0.0:12
</span></span><span class="line"><span class="cl">-device cirrus-vga,id<span class="o">=</span>video0,bus<span class="o">=</span>pci.0,addr<span class="o">=</span>0x2
</span></span></code></pre></div><ul>
<li>
<p><code>-enable-kvm</code>：表示启用硬件辅助虚拟化。</p>
</li>
<li>
<p><code>-name instance-00000024</code>：表示虚拟机的名称。</p>
</li>
<li>
<p><code>-machine pc-i440fx-trusty,accel=kvm,usb=off</code>：machine 是什么呢？其实就是计算机体系结构。不知道什么是体系结构的话，可以订阅极客时间的另一个专栏《深入浅出计算机组成原理》。
qemu 会模拟多种体系结构，常用的有普通 PC 机，也即 x86 的 32 位或者 64 位的体系结构、Mac 电脑 PowerPC 的体系结构、Sun 的体系结构、MIPS 的体系结构，精简指令集。如果使用 KVM hardware-assisted virtualization，也即 BIOS 中 VD-T 是打开的，则参数中 <code>accel=kvm</code>。如果不使用 <code>hardware-assisted virtualization</code>，用的是纯模拟，则有参数 <code>accel = tcg</code>，<code>-no-kvm</code>。</p>
</li>
<li>
<p><code>-cpu SandyBridge,+erms,+smep,+fsgsbase,+pdpe1gb,+rdrand,+f16c,+osxsave,+dca,+pcid,+pdcm,+xtpr,+tm2,+est,+smx,+vmx,+ds_cpl,+monitor,+dtes64,+pbe,+tm,+ht,+ss,+acpi,+ds,+vme</code>：表示设置 CPU，SandyBridge 是 Intel 处理器，后面的加号都是添加的 CPU 的参数，这些参数会显示在 /proc/cpuinfo 里面。</p>
</li>
<li>
<p><code>-m 2048</code>：表示内存。</p>
</li>
<li>
<p><code>-smp 1,sockets=1,cores=1,threads=1</code>：<code>SMP</code> 我们解析过，叫对称多处理器，和<code>NUMA</code> 对应。qemu 仿真了一个具有 1 个 <code>vcpu</code>，一个 <code>socket</code>，一个 <code>core</code>，一个 <code>threads</code> 的处理器。
<code>socket</code>、<code>core</code>、<code>threads</code> 是什么概念呢？<code>socket</code> 就是主板上插 CPU 的槽的数目，也即常说的“路”，<code>core</code> 就是我们平时说的“核”，即双核、4 核等。<code>thread</code> 就是每个 core 的硬件线程数，即超线程。举个具体的例子，某个服务器是：2 路 4 核超线程（一般默认为 2 个线程），通过 <code>cat /proc/cpuinfo</code>，我们看到的是 242=16 个<code>processor</code>，很多人也习惯成为 16 核了。</p>
</li>
<li>
<p><code>-rtc base=utc,driftfix=slew</code>：表示系统时间由参数 <code>-rtc</code> 指定。</p>
</li>
<li>
<p><code>-device cirrus-vga,id=video0,bus=pci.0,addr=0x2</code>：表示显示器用参数 <code>-vga</code> 设置，默认为 <code>cirrus</code>，它模拟了 <code>CL-GD5446PCI VGA card</code>。</p>
</li>
<li>
<p>有关网卡，使用 <code>-net</code> 参数和 <code>-device</code>。</p>
</li>
<li>
<p>从 HOST 角度：<code>-netdev tap,fd=32,id=hostnet0,vhost=on,vhostfd=37</code>。</p>
</li>
<li>
<p>从 GUEST 角度：<code>-device virtio-net-pci,netdev=hostnet0,id=net0,mac=fa:16:3e:d1:2d:99,bus=pci.0,addr=0x3</code>。</p>
</li>
<li>
<p>有关硬盘，使用 <code>-hda -hdb</code>，或者使用 <code>-drive</code> 和 <code>-device</code>。</p>
</li>
<li>
<p>从 HOST 角度：<code>-drive file=/var/lib/nova/instances/1f8e6f7e-5a70-4780-89c1-464dc0e7f308/disk,if=none,id=drive-virtio-disk0,format=qcow2,cache=none</code></p>
</li>
<li>
<p>从 GUEST 角度：<code>-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1</code></p>
</li>
<li>
<p><code>-vnc 0.0.0.0:12</code>：设置 VNC。</p>
</li>
</ul>
<h2 id="module_call_init初始化所有模块"><code>module_call_init</code>初始化所有模块</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="o">--&gt;</span> <span class="nf">qemu_init</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="o">--&gt;</span> <span class="nf">qemu_init_subsystems</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="o">--&gt;</span> <span class="nf">module_call_init</span><span class="p">()</span>
</span></span></code></pre></div><p>当虚拟机真的要使用物理资源的时候，对下面的物理机上的资源要进行请求，所以它的工作模式有点儿类似操作系统对接驱动。驱动要符合一定的格式，才能算操作系统的一个模块。同理，qemu 为了模拟各种各样的设备，也需要管理各种各样的模块，这些模块也需要符合一定的格式。</p>
<p>定义一个 qemu 模块会调用 <code>type_init</code>。例如，<code>kvm</code> 的模块要在 <code>accel/kvm/kvm-all.c</code> 文件里面实现。在这个文件里面，有一行下面的代码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">TypeInfo</span> <span class="n">kvm_accel_type</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">TYPE_KVM_ACCEL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">TYPE_ACCEL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">instance_init</span> <span class="o">=</span> <span class="n">kvm_accel_instance_init</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">class_init</span> <span class="o">=</span> <span class="n">kvm_accel_class_init</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">instance_size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">KVMState</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">kvm_type_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">type_register_static</span><span class="p">(</span><span class="o">&amp;</span><span class="n">kvm_accel_type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">type_init</span><span class="p">(</span><span class="n">kvm_type_init</span><span class="p">);</span>
</span></span></code></pre></div><p>找到<code>type_init</code>的定义</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define type_init(function) module_init(function, MODULE_INIT_QOM)
</span></span></span></code></pre></div><p>从代码里面的定义我们可以看出来，<code>type_init</code> 后面的参数是一个函数，调用 <code>type_init</code> 就相当于调用 <code>module_init</code>，在这里函数就是 <code>kvm_type_init</code>，类型就是 <code>MODULE_INIT_QOM</code>。</p>
<p>再查看一下<code>module_init</code>的定义</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//include/qemu/module.h
</span></span></span><span class="line"><span class="cl"><span class="cp">#define module_init(function, type)                                         \
</span></span></span><span class="line"><span class="cl"><span class="cp">static void __attribute__((constructor)) do_qemu_init_ ## function(void)    \
</span></span></span><span class="line"><span class="cl"><span class="cp">{                                                                           \
</span></span></span><span class="line"><span class="cl"><span class="cp">    register_module_init(function, type);                                   \
</span></span></span><span class="line"><span class="cl"><span class="cp">}
</span></span></span></code></pre></div><p><code>module_init</code> 最终要调用 <code>register_module_init</code>。属于 <code>MODULE_INIT_QOM</code> 这种类型的，有一个 <code>Module</code> 列表 <code>ModuleTypeList</code>，列表里面是一项一项的 <code>ModuleEntry</code>。<code>KVM</code> 就是其中一项，并且会初始化每一项的 <code>init</code> 函数为参数表示的函数 <code>fn</code>，也即 <code>KVM</code> 这个 <code>module</code> 的 <code>init</code> 函数就是 <code>kvm_type_init</code>。</p>
<p>当然，<code>MODULE_INIT_QOM</code> 这种类型会有很多很多的 <code>module</code>，从后面的代码我们可以看到，所有调用 <code>type_init</code> 的地方都注册了一个 <code>MODULE_INIT_QOM</code> 类型的 <code>Module</code>。</p>
<p>了解了 <code>Module</code> 的注册机制，我们继续回到 <code>qemu_init_subsystems</code> 函数中 <code>module_call_init</code> 的调用。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">qemu_init_subsystems</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">Error</span> <span class="o">*</span><span class="n">err</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">os_set_line_buffering</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nf">module_call_init</span><span class="p">(</span><span class="n">MODULE_INIT_TRACE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">qemu_init_cpu_list</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nf">qemu_init_cpu_loop</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nf">qemu_mutex_lock_iothread</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nf">atexit</span><span class="p">(</span><span class="n">qemu_run_exit_notifiers</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">module_call_init</span><span class="p">(</span><span class="n">MODULE_INIT_QOM</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">module_call_init</span><span class="p">(</span><span class="n">MODULE_INIT_MIGRATION</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// utils/module.c
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">module_call_init</span><span class="p">(</span><span class="n">module_init_type</span> <span class="n">type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">ModuleTypeList</span> <span class="o">*</span><span class="n">l</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ModuleEntry</span> <span class="o">*</span><span class="n">e</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">l</span> <span class="o">=</span> <span class="nf">find_type</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">QTAILQ_FOREACH</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">node</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">e</span><span class="o">-&gt;</span><span class="nf">init</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在 <code>module_call_init</code> 中，我们会找到 <code>MODULE_INIT_QOM</code> 这种类型对应的 <code>ModuleTypeList</code>，找出列表中所有的 <code>ModuleEntry</code>，然后调用每个 <code>ModuleEntry</code> 的 <code>init</code> 函数。这里需要注意的是，在 <code>module_call_init</code> 调用的这一步，所有 <code>Module</code> 的 <code>init</code> 函数都已经被调用过了。</p>
<p>后面我们会看到很多的 <code>Module</code>，当我们后面再次遇到时，需要意识到，它的 <code>init</code> 函数在这里也被调用过了。这里我们还是以对于 <code>kvm</code> 这个 <code>module</code> 为例子，看看它的 <code>init</code> 函数都做了哪些事情。我们会发现，其实它调用的是 <code>kvm_type_init</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">kvm_type_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">type_register_static</span><span class="p">(</span><span class="o">&amp;</span><span class="n">kvm_accel_type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">TypeImpl</span> <span class="o">*</span><span class="nf">type_register_static</span><span class="p">(</span><span class="k">const</span> <span class="n">TypeInfo</span> <span class="o">*</span><span class="n">info</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nf">type_register</span><span class="p">(</span><span class="n">info</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">TypeImpl</span> <span class="o">*</span><span class="nf">type_register</span><span class="p">(</span><span class="k">const</span> <span class="n">TypeInfo</span> <span class="o">*</span><span class="n">info</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">assert</span><span class="p">(</span><span class="n">info</span><span class="o">-&gt;</span><span class="n">parent</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nf">type_register_internal</span><span class="p">(</span><span class="n">info</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">TypeImpl</span> <span class="o">*</span><span class="nf">type_register_internal</span><span class="p">(</span><span class="k">const</span> <span class="n">TypeInfo</span> <span class="o">*</span><span class="n">info</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">TypeImpl</span> <span class="o">*</span><span class="n">ti</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span> <span class="o">=</span> <span class="nf">type_new</span><span class="p">(</span><span class="n">info</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">    <span class="nf">type_table_add</span><span class="p">(</span><span class="n">ti</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ti</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">TypeImpl</span> <span class="o">*</span><span class="nf">type_new</span><span class="p">(</span><span class="k">const</span> <span class="n">TypeInfo</span> <span class="o">*</span><span class="n">info</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">TypeImpl</span> <span class="o">*</span><span class="n">ti</span> <span class="o">=</span> <span class="nf">g_malloc0</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">ti</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">type_table_lookup</span><span class="p">(</span><span class="n">info</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">name</span> <span class="o">=</span> <span class="nf">g_strdup</span><span class="p">(</span><span class="n">info</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">parent</span> <span class="o">=</span> <span class="nf">g_strdup</span><span class="p">(</span><span class="n">info</span><span class="o">-&gt;</span><span class="n">parent</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">class_size</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">class_size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">instance_size</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">instance_size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">class_init</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">class_init</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">class_base_init</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">class_base_init</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">class_data</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">class_data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">instance_init</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">instance_init</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">instance_post_init</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">instance_post_init</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">instance_finalize</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">instance_finalize</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">abstract</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">abstract</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">interfaces</span> <span class="o">&amp;&amp;</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">interfaces</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">type</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">interfaces</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="kr">typename</span> <span class="o">=</span> <span class="nf">g_strdup</span><span class="p">(</span><span class="n">info</span><span class="o">-&gt;</span><span class="n">interfaces</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">num_interfaces</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">ti</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">type_table_add</span><span class="p">(</span><span class="n">TypeImpl</span> <span class="o">*</span><span class="n">ti</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">assert</span><span class="p">(</span><span class="o">!</span><span class="n">enumerating_types</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">g_hash_table_insert</span><span class="p">(</span><span class="nf">type_table_get</span><span class="p">(),</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">ti</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">ti</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">GHashTable</span> <span class="o">*</span><span class="nf">type_table_get</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">static</span> <span class="n">GHashTable</span> <span class="o">*</span><span class="n">type_table</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">type_table</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">type_table</span> <span class="o">=</span> <span class="nf">g_hash_table_new</span><span class="p">(</span><span class="n">g_str_hash</span><span class="p">,</span> <span class="n">g_str_equal</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">type_table</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="n">TypeInfo</span> <span class="n">kvm_accel_type</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">TYPE_KVM_ACCEL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">parent</span> <span class="o">=</span> <span class="n">TYPE_ACCEL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">class_init</span> <span class="o">=</span> <span class="n">kvm_accel_class_init</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">instance_size</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">KVMState</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>调用流程如下：虚线表示返回</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210907133931.svg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210907133931.svg" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>每一个 <code>Module</code> 既然要模拟某种设备，那应该定义一种类型 <code>TypeImpl</code> 来表示这些设备，这其实是一种<code>面向对象编程</code>的思路，只不过这里用的是纯 C 语言的实现，所以需要变相实现一下类和对象。</p>
<p><code>kvm_type_init</code> 会注册 <code>kvm_accel_type</code>，定义上面的代码，我们可以认为这样动态定义了一个类。这个类的名字是 <code>TYPE_KVM_ACCEL</code>，这个类有父类 <code>TYPE_ACCEL</code>，这个类的初始化应该调用函数 <code>kvm_accel_class_init</code>。如果用这个类声明一个对象，对象的大小应该是 <code>instance_size</code>。</p>
<p>在 <code>type_register_internal</code> 中，我们会根据 <code>kvm_accel_type</code> 这个 <code>TypeInfo</code>，创建一个<code>TypeImpl</code> 来表示这个新注册的类，也就是说，<code>TypeImpl</code> 才是我们想要声明的那个 <code>class</code>。在 qemu 里面，有一个全局的哈希表 <code>type_table</code>，用来存放所有定义的类。在 <code>type_new</code> 里面，我们先从全局表里面根据名字<code>type_table_lookup</code>查找找这个类。如果找到，说明这个类曾经被注册过，就报错；如果没有找到，说明这是一个新的类，则将 <code>TypeInfo</code> 里面信息填到 <code>TypeImpl</code> 里面。<code>type_table_add</code> 会将这个类注册到全局的表里面。到这里，我们注意，<code>class_init</code> 还没有被调用，也即这个类现在还处于纸面的状态。</p>
<p>这点更加像 Java 的反射机制了。在 Java 里面，对于一个类，首先我们写代码的时候要写一个 <code>class xxx</code> 的定义，编译好就放在<code>.class</code> 文件中，这也是出于纸面的状态。然后，Java 会有一个 <code>Class</code> 对象，用于读取和表示这个纸面上的 <code>class xxx</code>，可以生成真正的对象。</p>
<p>相同的过程在后面的代码中我们也可以看到，<code>class_init</code> 会生成<code>XXXClass</code>，就相当于 Java 里面的 <code>Class</code>对象，<code>TypeImpl</code> 还会有一个 <code>instance_init</code> 函数，相当于构造函数，用于根据 <code>XXXClass</code> 生成 <code>Object</code>，这就相当于 Java 反射里面最终创建的对象。和构造函数对应的还有 <code>instance_finalize</code>，相当于析构函数。</p>
<p>这一套反射机制放在 <code>qom</code> 文件夹下面，全称 <code>QEMU Object Model</code>，也即用 C 实现了一套<strong>面向对象的反射机制</strong>。</p>
<h2 id="初始化-machine">初始化 machine</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210913115046.svg">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210913115046.svg" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//vl.c
</span></span></span><span class="line"><span class="cl"><span class="nf">qemu_create_machine</span> <span class="p">(</span><span class="nf">select_machine</span><span class="p">());</span>
</span></span></code></pre></div><p>在创建 machine 之前，先要通过<code>select_machine</code>确定一个<code>machine</code>。<code>select_machine</code>又是怎么确定的呢，这就和我们命令行的输入有关，比如我们<code>-m spike</code>，那么这里就会选择<code>spike</code>作为<code>machine</code>。它的定义在<code>hw/riscv/spike.c</code>中。</p>
<p>在源码最后有这么一句，会和我们上面解析的<code>type_init</code> 是一样的，在全局的表里面注册了一个全局的名字是<code>spike</code>的纸面上的 <code>class</code>，也即 <code>TypeImpl</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">type_init</span><span class="p">(</span><span class="n">spike_machine_init_reqister_types</span><span class="p">)</span>
</span></span></code></pre></div><p>现在全局表中有这个纸面上的 <code>class</code> 了。我们回到 <code>select_machine</code>。</p>
<p>在 <code>select_machine</code> 中，有两种方式可以生成 <code>MachineClass</code>。一种方式是 <code>find_default_machine</code>，找一个默认的；另一种方式是 <code>machine_parse</code>，通过解析参数生成 <code>MachineClass</code>。无论哪种方式，都会调用 <code>object_class_get_list</code> 获得一个 <code>MachineClass</code> 的列表，然后在里面找。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="n">MachineClass</span> <span class="o">*</span><span class="nf">select_machine</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">GSList</span> <span class="o">*</span><span class="n">machines</span> <span class="o">=</span> <span class="nf">object_class_get_list</span><span class="p">(</span><span class="n">TYPE_MACHINE</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">MachineClass</span> <span class="o">*</span><span class="n">machine_class</span> <span class="o">=</span> <span class="nf">find_default_machine</span><span class="p">(</span><span class="n">machines</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">optarg</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">QemuOpts</span> <span class="o">*</span><span class="n">opts</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">Location</span> <span class="n">loc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">loc_push_none</span><span class="p">(</span><span class="o">&amp;</span><span class="n">loc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">opts</span> <span class="o">=</span> <span class="nf">qemu_get_machine_opts</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="nf">qemu_opts_loc_restore</span><span class="p">(</span><span class="n">opts</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">optarg</span> <span class="o">=</span> <span class="nf">qemu_opt_get</span><span class="p">(</span><span class="n">opts</span><span class="p">,</span> <span class="s">&#34;type&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">optarg</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">machine_class</span> <span class="o">=</span> <span class="nf">machine_parse</span><span class="p">(</span><span class="n">optarg</span><span class="p">,</span> <span class="n">machines</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">machine_class</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">error_report</span><span class="p">(</span><span class="s">&#34;No machine specified, and there is no default&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">error_printf</span><span class="p">(</span><span class="s">&#34;Use -machine help to list supported machines</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">loc_pop</span><span class="p">(</span><span class="o">&amp;</span><span class="n">loc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">g_slist_free</span><span class="p">(</span><span class="n">machines</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">machine_class</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">MachineClass</span> <span class="o">*</span><span class="nf">find_default_machine</span><span class="p">(</span><span class="n">GSList</span> <span class="o">*</span><span class="n">machines</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">GSList</span> <span class="o">*</span><span class="n">el</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">MachineClass</span> <span class="o">*</span><span class="n">default_machineclass</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">el</span> <span class="o">=</span> <span class="n">machines</span><span class="p">;</span> <span class="n">el</span><span class="p">;</span> <span class="n">el</span> <span class="o">=</span> <span class="n">el</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">MachineClass</span> <span class="o">*</span><span class="n">mc</span> <span class="o">=</span> <span class="n">el</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">mc</span><span class="o">-&gt;</span><span class="n">is_default</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nf">assert</span><span class="p">(</span><span class="n">default_machineclass</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">&amp;&amp;</span> <span class="s">&#34;Multiple default machines&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">default_machineclass</span> <span class="o">=</span> <span class="n">mc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">default_machineclass</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">MachineClass</span> <span class="o">*</span><span class="nf">machine_parse</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span> <span class="n">GSList</span> <span class="o">*</span><span class="n">machines</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MachineClass</span> <span class="o">*</span><span class="n">mc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">GSList</span> <span class="o">*</span><span class="n">el</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">is_help_option</span><span class="p">(</span><span class="n">name</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;Supported machines are:</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">machines</span> <span class="o">=</span> <span class="nf">g_slist_sort</span><span class="p">(</span><span class="n">machines</span><span class="p">,</span> <span class="n">machine_class_cmp</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="n">el</span> <span class="o">=</span> <span class="n">machines</span><span class="p">;</span> <span class="n">el</span><span class="p">;</span> <span class="n">el</span> <span class="o">=</span> <span class="n">el</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">MachineClass</span> <span class="o">*</span><span class="n">mc</span> <span class="o">=</span> <span class="n">el</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">mc</span><span class="o">-&gt;</span><span class="n">alias</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%-20s %s (alias of %s)</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">mc</span><span class="o">-&gt;</span><span class="n">alias</span><span class="p">,</span> <span class="n">mc</span><span class="o">-&gt;</span><span class="n">desc</span><span class="p">,</span> <span class="n">mc</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;%-20s %s%s%s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">mc</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">mc</span><span class="o">-&gt;</span><span class="n">desc</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                   <span class="n">mc</span><span class="o">-&gt;</span><span class="n">is_default</span> <span class="o">?</span> <span class="s">&#34; (default)&#34;</span> <span class="o">:</span> <span class="s">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                   <span class="n">mc</span><span class="o">-&gt;</span><span class="n">deprecation_reason</span> <span class="o">?</span> <span class="s">&#34; (deprecated)&#34;</span> <span class="o">:</span> <span class="s">&#34;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">mc</span> <span class="o">=</span> <span class="nf">find_machine</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">machines</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">mc</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">error_report</span><span class="p">(</span><span class="s">&#34;unsupported machine type&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">error_printf</span><span class="p">(</span><span class="s">&#34;Use -machine help to list supported machines</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">mc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>object_class_get_list</code> 定义如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">GSList</span> <span class="o">*</span><span class="nf">object_class_get_list</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">implements_type</span><span class="p">,</span><span class="kt">bool</span> <span class="n">include_abstract</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">GSList</span> <span class="o">*</span><span class="n">list</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">object_class_foreach</span><span class="p">(</span><span class="n">object_class_get_list_tramp</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                         <span class="n">implements_type</span><span class="p">,</span> <span class="n">include_abstract</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">list</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">list</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">object_class_foreach</span><span class="p">(</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">fn</span><span class="p">)(</span><span class="n">ObjectClass</span> <span class="o">*</span><span class="n">klass</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                          <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">implements_type</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">include_abstract</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                          <span class="kt">void</span> <span class="o">*</span><span class="n">opaque</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">OCFData</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="n">fn</span><span class="p">,</span> <span class="n">implements_type</span><span class="p">,</span> <span class="n">include_abstract</span><span class="p">,</span> <span class="n">opaque</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">enumerating_types</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">g_hash_table_foreach</span><span class="p">(</span><span class="nf">type_table_get</span><span class="p">(),</span> <span class="n">object_class_foreach_tramp</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">enumerating_types</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在全局表 <code>type_table_get()</code> 中，对于每一项 <code>TypeImpl</code>，我们都执行 <code>object_class_foreach_tramp</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">object_class_foreach_tramp</span><span class="p">(</span><span class="n">gpointer</span> <span class="n">key</span><span class="p">,</span> <span class="n">gpointer</span> <span class="n">value</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                                       <span class="n">gpointer</span> <span class="n">opaque</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">OCFData</span> <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="n">opaque</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">TypeImpl</span> <span class="o">*</span><span class="n">type</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">ObjectClass</span> <span class="o">*</span><span class="n">k</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">type_initialize</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">k</span> <span class="o">=</span> <span class="n">type</span><span class="o">-&gt;</span><span class="n">class</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">data</span><span class="o">-&gt;</span><span class="n">include_abstract</span> <span class="o">&amp;&amp;</span> <span class="n">type</span><span class="o">-&gt;</span><span class="n">abstract</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">data</span><span class="o">-&gt;</span><span class="n">implements_type</span> <span class="o">&amp;&amp;</span> 
</span></span><span class="line"><span class="cl">        <span class="o">!</span><span class="nf">object_class_dynamic_cast</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">data</span><span class="o">-&gt;</span><span class="n">implements_type</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">data</span><span class="o">-&gt;</span><span class="nf">fn</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">data</span><span class="o">-&gt;</span><span class="n">opaque</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在 <code>object_class_foreach_tramp</code> 中，会调用将 <code>type_initialize</code>，这里面会调用 <code>class_init</code> 将纸面上的 <code>class</code> 也即 <code>TypeImpl</code> 变为 <code>ObjectClass</code>，<code>ObjectClass</code> 是所有<code>Class</code> 类的祖先，<code>MachineClass</code> 是它的子类。</p>
<p>因为在 <code>machine</code> 的命令行里面，我们指定了名字为<code>spike</code>，就肯定能够找到我们注册过了的 <code>TypeImpl</code>，并调用它的 <code>class_init</code> 函数。</p>
<p>所以，当 <code>select_machine</code> 执行完毕后，就有一个 <code>MachineClass</code> 了。</p>
<p>接着，我们回到 <code>qemu_create_machine</code> 中的<code>object_new_with_class</code>。这就很好理解了，<code>MachineClass</code> 是一个 <code>Class</code> 类，接下来应该通过它生成一个 <code>Instance</code>，也即对象，这就是 <code>object_new_with_class</code> 的作用。</p>
<p><code>object_new_with_class</code> 中，<code>TypeImpl</code> 的 <code>instance_init</code> 会被调用，创建一个对象。<code>current_machine</code> 就是这个对象，它的类型是<code>MachineState</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">Object</span> <span class="o">*</span><span class="nf">object_new_with_class</span><span class="p">(</span><span class="n">ObjectClass</span> <span class="o">*</span><span class="n">klass</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nf">object_new_with_type</span><span class="p">(</span><span class="n">klass</span><span class="o">-&gt;</span><span class="n">type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="n">Object</span> <span class="o">*</span><span class="nf">object_new_with_type</span><span class="p">(</span><span class="n">Type</span> <span class="n">type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">Object</span> <span class="o">*</span><span class="n">obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">type_initialize</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">obj</span> <span class="o">=</span> <span class="nf">g_malloc</span><span class="p">(</span><span class="n">type</span><span class="o">-&gt;</span><span class="n">instance_size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nf">object_initialize_with_type</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">type</span><span class="o">-&gt;</span><span class="n">instance_size</span><span class="p">,</span> <span class="n">type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">obj</span><span class="o">-&gt;</span><span class="n">free</span> <span class="o">=</span> <span class="n">g_free</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>至此，绕了这么大一圈，有关体系结构的对象才创建完毕，接下来很多的设备的初始化，包括 CPU 和内存的初始化，都是围绕着体系结构的对象来的，后面我们会常常看到<code>current_machine</code>。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220308180036.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20220308180036.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="参考">参考</h2>
<p><a href="https://www.cnblogs.com/nm90/p/15661202.html">Qemu CPU 虚拟化 - 人生一世，草木一秋。 - 博客园</a>
<a href="https://www.cnblogs.com/LoyenWang/p/13796537.html">【原创】Linux 虚拟化 KVM-Qemu 分析（四）之 CPU 虚拟化（2） - LoyenWang - 博客园</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 操作系统-进程管理</title>
      <link>https://lifeislife.cn/posts/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/</link>
      <pubDate>Mon, 30 Aug 2021 09:41:50 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/</guid>
      <description>&lt;h2 id=&#34;进程&#34;&gt;进程&lt;/h2&gt;
&lt;h3 id=&#34;源码&#34;&gt;源码&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//process.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;create_process&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;program&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;create_process&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;program&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;pid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child_pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;child_pid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fork&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;child_pid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;child_pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;execvp&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;program&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;abort&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这里，我们创建的子程序运行了一个最最简单的命令 &lt;code&gt;ls&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//createprocess.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;create_process&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;program&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;**&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s&#34;&gt;&amp;#34;ls&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s&#34;&gt;&amp;#34;-l&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s&#34;&gt;&amp;#34;/etc/yum.repos.d/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;create_process&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ls&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;编译&#34;&gt;编译&lt;/h3&gt;
&lt;p&gt;CPU 看不懂源码里的函数，命令，CPU 只认二进制数据，所以源码需要翻译成&lt;code&gt;01&lt;/code&gt;二进制数据，这个过程就是**编译（Compile）**的过程。&lt;/p&gt;
&lt;p&gt;编译出的文件好比一个公司的项目执行计划书，你要把一个项目执行好，计划书得有章法，有一定格式。在 Linux 下，二进制程序也有这样的格式，叫&lt;strong&gt;ELF&lt;/strong&gt;（Executeable and Linkable Format，可执行与可链接格式），这个格式可以根据编译的结果不同，分为不同的格式。&lt;/p&gt;
&lt;h3 id=&#34;elf-可重定位文件&#34;&gt;ELF-可重定位文件&lt;/h3&gt;
&lt;p&gt;下图展示了如何从源码到二进制文件的转化&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810085445.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810085445.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcc -c -fPIC process.c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcc -c -fPIC createprocess.c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-fPIC&lt;/code&gt;作用于编译阶段，告诉编译器产生与位置无关代码 (Position-Independent Code)。产生的代码中，没有绝对地址，全部使用相对地址，故而代码可以被加载器加载到内存的任意位置，都可以正确的执行。&lt;/p&gt;
&lt;p&gt;在编译的时候，先做&lt;strong&gt;预处理&lt;/strong&gt;工作，例如将头文件嵌入到正文中，将定义的宏展开，然后就是真正的编译过程，最终编译成为&lt;code&gt;.o&lt;/code&gt;文件，这就是&lt;code&gt;ELF&lt;/code&gt;的第一种类型，&lt;strong&gt;可重定位文件&lt;/strong&gt;（Relocatable File）。文件格式如下，&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810085520.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810085520.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ELF&lt;/code&gt; 文件的头是用于描述整个文件的。这个文件格式在内核中有定义，分别为 &lt;code&gt;struct elf32_hdr&lt;/code&gt; 和 &lt;code&gt;struct elf64_hdr&lt;/code&gt;。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;section&lt;/th&gt;
					&lt;th&gt;内容&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;.text&lt;/td&gt;
					&lt;td&gt;放编译好的二进制可执行代码&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;.data&lt;/td&gt;
					&lt;td&gt;已经初始化好的全局变量（临时变量放在栈里）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;.rodata&lt;/td&gt;
					&lt;td&gt;只读数据，例如字符串常量、const 的变量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;.bss&lt;/td&gt;
					&lt;td&gt;未初始化全局变量，运行时会置 0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;.symtab&lt;/td&gt;
					&lt;td&gt;符号表，记录的则是函数和变量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;.strtab&lt;/td&gt;
					&lt;td&gt;字符串表、字符串常量和变量名&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;第一种 ELF 文件叫可重定位文件，为啥可重定位？我们可以想象一下，这个编译好的代码和变量，将来&lt;strong&gt;加载到内存&lt;/strong&gt;里面的时候，都是要加载到一定位置的。比如说，调用一个函数，其实就是跳到这个函数所在的代码位置执行；再比如修改一个全局变量，也是要到变量的位置那里去修改。但是现在这个时候，还是&lt;code&gt;.o&lt;/code&gt;文件，不是一个可以直接运行的程序，这里面只是部分代码片段。&lt;/p&gt;
&lt;p&gt;例如这里的 &lt;code&gt;create_process&lt;/code&gt;函数，将来被谁调用，在哪里调用都不清楚，就更别提确定位置了。所以，&lt;code&gt;.o&lt;/code&gt;里面的位置是不确定的，但是必须是可重新定位的，因为它将来是要做函数库的嘛，就是一块砖，哪里需要哪里搬，搬到哪里就重新定位这些代码、变量的位置。&lt;/p&gt;
&lt;h4 id=&#34;elf-可执行文件&#34;&gt;ELF-可执行文件&lt;/h4&gt;
&lt;p&gt;要让&lt;code&gt;create_process&lt;/code&gt;这个函数作为库文件重用，需要将其形成库文件，最简单的类型是静态链接库&lt;code&gt;.a&lt;/code&gt;文件，它将一系列&lt;code&gt;.o&lt;/code&gt;文件归档为一个文件。使用&lt;code&gt;ar&lt;/code&gt;命令创建&lt;code&gt;.a&lt;/code&gt;文件。&lt;a href=&#34;&#34;&gt;使用方法看这里&lt;/a&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ar cr libstaticprocess.a process.o
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然这里 &lt;code&gt;libstaticprocess.a&lt;/code&gt; 里面只有一个&lt;code&gt;.o&lt;/code&gt;，但是实际情况可以有多个&lt;code&gt;.o&lt;/code&gt;。当有程序要使用这个静态连接库的时候，会将.o 文件提取出来，链接到程序中。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcc -o staticcreateprocess createprocess.o -L. -lstaticprocess
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-L&lt;/code&gt;表示在当前目录下找&lt;code&gt;.a&lt;/code&gt;文件，&lt;code&gt;-lstaticprocess&lt;/code&gt; 会自动补全文件名，比如加前缀 &lt;code&gt;lib&lt;/code&gt;，后缀&lt;code&gt;.a&lt;/code&gt;，变成 &lt;code&gt;libstaticprocess.a&lt;/code&gt;，找到这个&lt;code&gt;.a&lt;/code&gt;文件后，将里面的 process.o 取出来，和 &lt;code&gt;createprocess.o&lt;/code&gt; 做一个链接，形成二进制执行文件 &lt;code&gt;staticcreateprocess&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在链接过程中，重定位就起作用了，在&lt;code&gt;createprocess.o&lt;/code&gt;里调用了&lt;code&gt;create_process&lt;/code&gt;函数，但是不能确定位置，现在将&lt;code&gt;process.o&lt;/code&gt;合并进来，就知道位置了。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810114727.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810114727.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;这个格式和&lt;code&gt;.o&lt;/code&gt; 文件大致相似，还是分成一个个的 &lt;code&gt;section&lt;/code&gt;，并且被节头表描述。只不过这些&lt;code&gt;section&lt;/code&gt; 是多个&lt;code&gt;.o&lt;/code&gt; 文件合并过的。但是这个时候，这个文件已经是马上就可以加载到内存里面执行的文件了，因而这些 &lt;code&gt;section&lt;/code&gt; 被分成了需要加载到内存里面的&lt;strong&gt;代码段&lt;/strong&gt;、&lt;strong&gt;数据段&lt;/strong&gt;和&lt;strong&gt;不需要加载&lt;/strong&gt;到内存里面的部分，将小的 &lt;code&gt;section&lt;/code&gt; 合成了大的段 &lt;code&gt;segment&lt;/code&gt;，并且在最前面加一个&lt;strong&gt;段头表&lt;/strong&gt;（Segment Header Table）。&lt;/p&gt;
&lt;p&gt;在代码里面的定义为 &lt;code&gt;struct elf32_phdr&lt;/code&gt;和 &lt;code&gt;struct elf64_phdr&lt;/code&gt;，这里面除了有对于段的描述之外，最重要的是 &lt;code&gt;p_vaddr&lt;/code&gt;，这个是这个段加载到内存的虚拟地址。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;ELF&lt;/code&gt; 头里面，有一项 &lt;code&gt;e_entry&lt;/code&gt;，也是个虚拟地址，是这个&lt;strong&gt;程序运行的入口&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id=&#34;elf-共享对象文件&#34;&gt;ELF-共享对象文件&lt;/h4&gt;
&lt;p&gt;静态库一旦被链接，代码和变量的&lt;code&gt;section&lt;/code&gt;会被合并，所以运行时不依赖静态库文件，但是缺点就是，相同代码段被多个程序使用，在&lt;strong&gt;内存里会有多份&lt;/strong&gt;，而且&lt;strong&gt;静态库更新需要重新编译&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;因而就出现了另一种，&lt;strong&gt;动态链接库&lt;/strong&gt;（Shared Libraries），不仅仅是一组对象文件的简单归档，而是多个对象文件的重新组合，可被多个程序共享。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcc -shared -fPIC -o libdynamicprocess.so process.o
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当一个动态链接库被链接到一个程序文件中的时候，最后的程序文件并不包括动态链接库中的代码，而仅仅包括对动态链接库的引用，并且不保存动态链接库的全路径，仅仅保存动态链接库的名称。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcc -o dynamiccreateprocess createprocess.o -L. -ldynamicprocess
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当运行这个程序的时候，首先寻找动态链接库，然后加载它。默认情况下，系统在 &lt;code&gt;/lib&lt;/code&gt; 和&lt;code&gt;/usr/lib&lt;/code&gt; 文件夹下寻找动态链接库。如果找不到就会报错，我们可以设定 &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt;环境变量，程序运行时会在此环境变量指定的文件夹下寻找动态链接库。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# export LD_LIBRARY_PATH=.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# ./dynamiccreateprocess&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# total 40&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rw&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--.&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1572&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Oct&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;24&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;18&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;38&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CentOS&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Base&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;repo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;动态链接库，就是&lt;code&gt;ELF&lt;/code&gt;的第三种类型，&lt;strong&gt;共享对象文件&lt;/strong&gt;（Shared Object）。&lt;/p&gt;
&lt;p&gt;文件格式和上两种文件稍有不同，首先，多了一个&lt;code&gt;.interp&lt;/code&gt;的 &lt;code&gt;Segment&lt;/code&gt;，这里面是 &lt;code&gt;ld-linux.so&lt;/code&gt;，这是动态链接器，也就是说，运行时的链接动作都是它做的。&lt;/p&gt;
&lt;p&gt;另外，&lt;code&gt;ELF&lt;/code&gt;文件中还多了两个&lt;code&gt;section&lt;/code&gt;，一个是&lt;code&gt;.plt&lt;/code&gt;，&lt;strong&gt;过程链接表&lt;/strong&gt;（Procedure Linkage Table，PLT），一个是。&lt;code&gt;got.plt&lt;/code&gt;，&lt;strong&gt;全局偏移量表&lt;/strong&gt;（Global Offset Table，GOT）。&lt;/p&gt;
&lt;h3 id=&#34;运行&#34;&gt;运行&lt;/h3&gt;
&lt;p&gt;在内核中，有&lt;code&gt;linux_binfmt elf_format&lt;/code&gt;数据结构定义了加载 ELF 的方法，使用&lt;code&gt;load_elf_binary&lt;/code&gt;加载二进制文件，该函数由&lt;code&gt;do_execve&lt;/code&gt;调用，学过系统调用知道&lt;code&gt;exec&lt;/code&gt;调用了&lt;code&gt;do_execve&lt;/code&gt;函数。所以流程为&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;do_execve&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;load_elf_binary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;进程树&#34;&gt;进程树&lt;/h4&gt;
&lt;p&gt;所有进程都是从父进程 fork 来的，祖宗进程就是&lt;code&gt;init&lt;/code&gt; 进程。&lt;/p&gt;
&lt;p&gt;系统启动之后，&lt;code&gt;init&lt;/code&gt; 进程会启动很多的&lt;code&gt;daemon&lt;/code&gt; 进程，为系统运行提供服务，然后就是启动 &lt;code&gt;getty&lt;/code&gt;，让用户登录，登录后运行 &lt;code&gt;shell&lt;/code&gt;，用户启动的进程都是通过 &lt;code&gt;shell&lt;/code&gt;运行的，从而形成了一棵进程树。&lt;/p&gt;
&lt;p&gt;我们可以通过 &lt;code&gt;ps -ef&lt;/code&gt;命令查看当前系统启动的进程，我们会发现有三类进程。&lt;code&gt;PID 1&lt;/code&gt; 的进程就是我们的&lt;code&gt;init&lt;/code&gt;进程 &lt;code&gt;systemd&lt;/code&gt;，&lt;code&gt;PID 2&lt;/code&gt; 的进程是内核线程 &lt;code&gt;kthreadd&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;内核态进程的&lt;code&gt;PPID&lt;/code&gt;祖先进程都是 2 号进程，用户态进程祖先进程都是 1 号进程，&lt;code&gt;tty&lt;/code&gt;列是问号的，说明是后台服务进程。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810143343.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810143343.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;进程数据结构&#34;&gt;进程数据结构&lt;/h2&gt;
&lt;p&gt;在 Linux 里面，无论是进程还是线程，到了内核里面，我们统一都叫任务（Task），由一个统一的结构&lt;code&gt;task_struct&lt;/code&gt;进行管理。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826183622.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826183622.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;每个任务应该包含的字段：&lt;/p&gt;
&lt;h3 id=&#34;任务-id&#34;&gt;任务 ID&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pid_t pid; #process id
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pid_t tgid; #thread group ID
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;struct task_struct *group_leader; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为何要有这么多 ID，一个不够吗？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以方便任务展示，比如在命令行中 ps 显示所有进程，只显示&lt;code&gt;pid_t pid&lt;/code&gt;，而不会把所有内部线程摊开展示，这样太碍眼。&lt;/li&gt;
&lt;li&gt;方便下达命令，当我 kill 一个进程时，我们是对整个进程发送信号，但是有时候一些命令只需要对某个线程发送信号。&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;信号处理&#34;&gt;信号处理&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Signal handlers: */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;signal_struct&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sighand_struct&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sighand&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;sigset_t&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;blocked&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;sigset_t&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;real_blocked&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;sigset_t&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;saved_sigmask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sigpending&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;pending&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;sas_ss_sp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;sas_ss_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;sas_ss_flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里定义了哪些信号被阻塞暂不处理（blocked），哪些信号尚等待处理（pending），哪些信号正在通过信号处理函数进行处理（sighand）。处理的结果可以是忽略，可以是结束进程等等。&lt;/p&gt;
&lt;h3 id=&#34;任务状态&#34;&gt;任务状态&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;volatile long state;    /* -1 unrunnable, 0 runnable, &amp;gt;0 stopped */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;int exit_state;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unsigned int flags;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;state&lt;/code&gt;可取值定义如下&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Used in tsk-&amp;gt;state: */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_RUNNING                    0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_INTERRUPTIBLE              1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_UNINTERRUPTIBLE            2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define __TASK_STOPPED                  4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define __TASK_TRACED                   8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Used in tsk-&amp;gt;exit_state: */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define EXIT_DEAD                       16
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define EXIT_ZOMBIE                     32
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define EXIT_TRACE                      (EXIT_ZOMBIE | EXIT_DEAD)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Used in tsk-&amp;gt;state again: */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_DEAD                       64
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_WAKEKILL                   128
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_WAKING                     256
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_PARKED                     512
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_NOLOAD                     1024
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_NEW                        2048
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define TASK_STATE_MAX                  4096
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以发现 Linux 通过 bitset 方式设置状态，当前什么状态，哪一位就置 1。&lt;/p&gt;
&lt;h3 id=&#34;进程调度&#34;&gt;进程调度&lt;/h3&gt;
&lt;p&gt;进程的状态切换往往涉及调度，下面这些字段都是用于调度的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 是否在运行队列上
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;on_rq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 优先级
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;prio&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;static_prio&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;normal_prio&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;rt_priority&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 调度器类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sched_class&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sched_class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 调度实体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sched_entity&lt;/span&gt;       &lt;span class=&#34;n&#34;&gt;se&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sched_rt_entity&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;rt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sched_dl_entity&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;dl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 调度策略
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;policy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 可以使用哪些 CPU
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;nr_cpus_allowed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;cpumask_t&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;cpus_allowed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sched_info&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;sched_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;运行统计信息&#34;&gt;运行统计信息&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;u64&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;utime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 用户态消耗的 CPU 时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;u64&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;stime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 内核态消耗的 CPU 时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;nvcsw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 自愿 (voluntary) 上下文切换计数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;nivcsw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 非自愿 (involuntary) 上下文切换计数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;u64&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 进程启动时间，不包含睡眠时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;u64&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;real_start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 进程启动时间，包含睡眠时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;进程亲缘关系&#34;&gt;进程亲缘关系&lt;/h3&gt;
&lt;p&gt;进程有棵进程树，所以有亲缘关系。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task_struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__rcu&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;real_parent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* real parent process */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;task_struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__rcu&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;cm&#34;&gt;/* recipient of SIGCHLD, wait4() reports */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;list_head&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;children&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;      &lt;span class=&#34;cm&#34;&gt;/* list of my children */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;list_head&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sibling&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;cm&#34;&gt;/* linkage in my parent&amp;#39;s children list */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通常情况下，&lt;code&gt;real_parent&lt;/code&gt; 和 &lt;code&gt;parent&lt;/code&gt; 是一样的，但是也会有另外的情况存在。例如，&lt;code&gt;bash&lt;/code&gt; 创建一个进程，那进程的 parent 和 &lt;code&gt;real_parent&lt;/code&gt; 就都是 &lt;code&gt;bash&lt;/code&gt;。如果在 bash 上使用 &lt;code&gt;GDB&lt;/code&gt; 来 &lt;code&gt;debug&lt;/code&gt; 一个进程，这个时候 &lt;code&gt;GDB&lt;/code&gt; 是 &lt;code&gt;real_parent&lt;/code&gt;，&lt;code&gt;bash&lt;/code&gt; 是这个进程的 &lt;code&gt;parent&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;进程权限&#34;&gt;进程权限&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Objective and real subjective task credentials (COW): */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cred&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__rcu&lt;/span&gt;         &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;real_cred&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Effective (overridable) subjective task credentials (COW): */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cred&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__rcu&lt;/span&gt;   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;real_cred&lt;/code&gt; 就是说明谁能操作我这个进程，而 &lt;code&gt;cred&lt;/code&gt; 就是说明我这个进程能够操作谁。&lt;/p&gt;
&lt;p&gt;总结到一起，&lt;code&gt;task_struct&lt;/code&gt;结构图如下，&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826190834.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826190834.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="进程">进程</h2>
<h3 id="源码">源码</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">//process.c
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/types.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="kt">int</span> <span class="nf">create_process</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span> <span class="n">program</span><span class="p">,</span> <span class="kt">char</span><span class="o">**</span> <span class="n">arg_list</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">create_process</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span> <span class="n">program</span><span class="p">,</span> <span class="kt">char</span><span class="o">**</span> <span class="n">arg_list</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">pid_t</span> <span class="n">child_pid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">child_pid</span> <span class="o">=</span> <span class="n">fork</span> <span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">child_pid</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">child_pid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> 
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">execvp</span> <span class="p">(</span><span class="n">program</span><span class="p">,</span> <span class="n">arg_list</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">abort</span> <span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在这里，我们创建的子程序运行了一个最最简单的命令 <code>ls</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="c1">//createprocess.c
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/types.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="kt">int</span> <span class="nf">create_process</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span> <span class="n">program</span><span class="p">,</span> <span class="kt">char</span><span class="o">**</span> <span class="n">arg_list</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span><span class="o">*</span> <span class="n">arg_list</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;ls&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;-l&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;/etc/yum.repos.d/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nb">NULL</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="n">create_process</span> <span class="p">(</span><span class="s">&#34;ls&#34;</span><span class="p">,</span> <span class="n">arg_list</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="编译">编译</h3>
<p>CPU 看不懂源码里的函数，命令，CPU 只认二进制数据，所以源码需要翻译成<code>01</code>二进制数据，这个过程就是**编译（Compile）**的过程。</p>
<p>编译出的文件好比一个公司的项目执行计划书，你要把一个项目执行好，计划书得有章法，有一定格式。在 Linux 下，二进制程序也有这样的格式，叫<strong>ELF</strong>（Executeable and Linkable Format，可执行与可链接格式），这个格式可以根据编译的结果不同，分为不同的格式。</p>
<h3 id="elf-可重定位文件">ELF-可重定位文件</h3>
<p>下图展示了如何从源码到二进制文件的转化</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810085445.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810085445.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">gcc -c -fPIC process.c
</span></span><span class="line"><span class="cl">gcc -c -fPIC createprocess.c
</span></span></code></pre></div><p><code>-fPIC</code>作用于编译阶段，告诉编译器产生与位置无关代码 (Position-Independent Code)。产生的代码中，没有绝对地址，全部使用相对地址，故而代码可以被加载器加载到内存的任意位置，都可以正确的执行。</p>
<p>在编译的时候，先做<strong>预处理</strong>工作，例如将头文件嵌入到正文中，将定义的宏展开，然后就是真正的编译过程，最终编译成为<code>.o</code>文件，这就是<code>ELF</code>的第一种类型，<strong>可重定位文件</strong>（Relocatable File）。文件格式如下，</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810085520.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810085520.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p><code>ELF</code> 文件的头是用于描述整个文件的。这个文件格式在内核中有定义，分别为 <code>struct elf32_hdr</code> 和 <code>struct elf64_hdr</code>。</p>
<table>
	<thead>
			<tr>
					<th>section</th>
					<th>内容</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>.text</td>
					<td>放编译好的二进制可执行代码</td>
			</tr>
			<tr>
					<td>.data</td>
					<td>已经初始化好的全局变量（临时变量放在栈里）</td>
			</tr>
			<tr>
					<td>.rodata</td>
					<td>只读数据，例如字符串常量、const 的变量</td>
			</tr>
			<tr>
					<td>.bss</td>
					<td>未初始化全局变量，运行时会置 0</td>
			</tr>
			<tr>
					<td>.symtab</td>
					<td>符号表，记录的则是函数和变量</td>
			</tr>
			<tr>
					<td>.strtab</td>
					<td>字符串表、字符串常量和变量名</td>
			</tr>
	</tbody>
</table>
<p>第一种 ELF 文件叫可重定位文件，为啥可重定位？我们可以想象一下，这个编译好的代码和变量，将来<strong>加载到内存</strong>里面的时候，都是要加载到一定位置的。比如说，调用一个函数，其实就是跳到这个函数所在的代码位置执行；再比如修改一个全局变量，也是要到变量的位置那里去修改。但是现在这个时候，还是<code>.o</code>文件，不是一个可以直接运行的程序，这里面只是部分代码片段。</p>
<p>例如这里的 <code>create_process</code>函数，将来被谁调用，在哪里调用都不清楚，就更别提确定位置了。所以，<code>.o</code>里面的位置是不确定的，但是必须是可重新定位的，因为它将来是要做函数库的嘛，就是一块砖，哪里需要哪里搬，搬到哪里就重新定位这些代码、变量的位置。</p>
<h4 id="elf-可执行文件">ELF-可执行文件</h4>
<p>要让<code>create_process</code>这个函数作为库文件重用，需要将其形成库文件，最简单的类型是静态链接库<code>.a</code>文件，它将一系列<code>.o</code>文件归档为一个文件。使用<code>ar</code>命令创建<code>.a</code>文件。<a href="">使用方法看这里</a>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ar cr libstaticprocess.a process.o
</span></span></code></pre></div><p>虽然这里 <code>libstaticprocess.a</code> 里面只有一个<code>.o</code>，但是实际情况可以有多个<code>.o</code>。当有程序要使用这个静态连接库的时候，会将.o 文件提取出来，链接到程序中。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">gcc -o staticcreateprocess createprocess.o -L. -lstaticprocess
</span></span></code></pre></div><p><code>-L</code>表示在当前目录下找<code>.a</code>文件，<code>-lstaticprocess</code> 会自动补全文件名，比如加前缀 <code>lib</code>，后缀<code>.a</code>，变成 <code>libstaticprocess.a</code>，找到这个<code>.a</code>文件后，将里面的 process.o 取出来，和 <code>createprocess.o</code> 做一个链接，形成二进制执行文件 <code>staticcreateprocess</code>。</p>
<p>在链接过程中，重定位就起作用了，在<code>createprocess.o</code>里调用了<code>create_process</code>函数，但是不能确定位置，现在将<code>process.o</code>合并进来，就知道位置了。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810114727.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810114727.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>这个格式和<code>.o</code> 文件大致相似，还是分成一个个的 <code>section</code>，并且被节头表描述。只不过这些<code>section</code> 是多个<code>.o</code> 文件合并过的。但是这个时候，这个文件已经是马上就可以加载到内存里面执行的文件了，因而这些 <code>section</code> 被分成了需要加载到内存里面的<strong>代码段</strong>、<strong>数据段</strong>和<strong>不需要加载</strong>到内存里面的部分，将小的 <code>section</code> 合成了大的段 <code>segment</code>，并且在最前面加一个<strong>段头表</strong>（Segment Header Table）。</p>
<p>在代码里面的定义为 <code>struct elf32_phdr</code>和 <code>struct elf64_phdr</code>，这里面除了有对于段的描述之外，最重要的是 <code>p_vaddr</code>，这个是这个段加载到内存的虚拟地址。</p>
<p>在 <code>ELF</code> 头里面，有一项 <code>e_entry</code>，也是个虚拟地址，是这个<strong>程序运行的入口</strong>。</p>
<h4 id="elf-共享对象文件">ELF-共享对象文件</h4>
<p>静态库一旦被链接，代码和变量的<code>section</code>会被合并，所以运行时不依赖静态库文件，但是缺点就是，相同代码段被多个程序使用，在<strong>内存里会有多份</strong>，而且<strong>静态库更新需要重新编译</strong>。</p>
<p>因而就出现了另一种，<strong>动态链接库</strong>（Shared Libraries），不仅仅是一组对象文件的简单归档，而是多个对象文件的重新组合，可被多个程序共享。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">gcc -shared -fPIC -o libdynamicprocess.so process.o
</span></span></code></pre></div><p>当一个动态链接库被链接到一个程序文件中的时候，最后的程序文件并不包括动态链接库中的代码，而仅仅包括对动态链接库的引用，并且不保存动态链接库的全路径，仅仅保存动态链接库的名称。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">gcc -o dynamiccreateprocess createprocess.o -L. -ldynamicprocess
</span></span></code></pre></div><p>当运行这个程序的时候，首先寻找动态链接库，然后加载它。默认情况下，系统在 <code>/lib</code> 和<code>/usr/lib</code> 文件夹下寻找动态链接库。如果找不到就会报错，我们可以设定 <code>LD_LIBRARY_PATH</code>环境变量，程序运行时会在此环境变量指定的文件夹下寻找动态链接库。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="c1"># export LD_LIBRARY_PATH=.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ./dynamiccreateprocess</span>
</span></span><span class="line"><span class="cl"><span class="c1"># total 40</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="n">r</span><span class="o">--</span><span class="n">r</span><span class="o">--.</span> <span class="mi">1</span> <span class="n">root</span> <span class="n">root</span> <span class="mi">1572</span> <span class="n">Oct</span> <span class="mi">24</span> <span class="mi">18</span><span class="p">:</span><span class="mi">38</span> <span class="n">CentOS</span><span class="o">-</span><span class="n">Base</span><span class="o">.</span><span class="n">repo</span>
</span></span><span class="line"><span class="cl"><span class="o">......</span>
</span></span></code></pre></div><p>动态链接库，就是<code>ELF</code>的第三种类型，<strong>共享对象文件</strong>（Shared Object）。</p>
<p>文件格式和上两种文件稍有不同，首先，多了一个<code>.interp</code>的 <code>Segment</code>，这里面是 <code>ld-linux.so</code>，这是动态链接器，也就是说，运行时的链接动作都是它做的。</p>
<p>另外，<code>ELF</code>文件中还多了两个<code>section</code>，一个是<code>.plt</code>，<strong>过程链接表</strong>（Procedure Linkage Table，PLT），一个是。<code>got.plt</code>，<strong>全局偏移量表</strong>（Global Offset Table，GOT）。</p>
<h3 id="运行">运行</h3>
<p>在内核中，有<code>linux_binfmt elf_format</code>数据结构定义了加载 ELF 的方法，使用<code>load_elf_binary</code>加载二进制文件，该函数由<code>do_execve</code>调用，学过系统调用知道<code>exec</code>调用了<code>do_execve</code>函数。所以流程为</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">exec</span><span class="o">-&gt;</span><span class="n">do_execve</span><span class="o">-&gt;</span><span class="n">load_elf_binary</span>
</span></span></code></pre></div><h4 id="进程树">进程树</h4>
<p>所有进程都是从父进程 fork 来的，祖宗进程就是<code>init</code> 进程。</p>
<p>系统启动之后，<code>init</code> 进程会启动很多的<code>daemon</code> 进程，为系统运行提供服务，然后就是启动 <code>getty</code>，让用户登录，登录后运行 <code>shell</code>，用户启动的进程都是通过 <code>shell</code>运行的，从而形成了一棵进程树。</p>
<p>我们可以通过 <code>ps -ef</code>命令查看当前系统启动的进程，我们会发现有三类进程。<code>PID 1</code> 的进程就是我们的<code>init</code>进程 <code>systemd</code>，<code>PID 2</code> 的进程是内核线程 <code>kthreadd</code>。</p>
<p>内核态进程的<code>PPID</code>祖先进程都是 2 号进程，用户态进程祖先进程都是 1 号进程，<code>tty</code>列是问号的，说明是后台服务进程。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810143343.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810143343.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="进程数据结构">进程数据结构</h2>
<p>在 Linux 里面，无论是进程还是线程，到了内核里面，我们统一都叫任务（Task），由一个统一的结构<code>task_struct</code>进行管理。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826183622.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826183622.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>每个任务应该包含的字段：</p>
<h3 id="任务-id">任务 ID</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">pid_t pid; #process id
</span></span><span class="line"><span class="cl">pid_t tgid; #thread group ID
</span></span><span class="line"><span class="cl">struct task_struct *group_leader; 
</span></span></code></pre></div><p>为何要有这么多 ID，一个不够吗？</p>
<ul>
<li>可以方便任务展示，比如在命令行中 ps 显示所有进程，只显示<code>pid_t pid</code>，而不会把所有内部线程摊开展示，这样太碍眼。</li>
<li>方便下达命令，当我 kill 一个进程时，我们是对整个进程发送信号，但是有时候一些命令只需要对某个线程发送信号。</li>
<li></li>
</ul>
<h3 id="信号处理">信号处理</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* Signal handlers: */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">signal_struct</span>    <span class="o">*</span><span class="n">signal</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sighand_struct</span>    <span class="o">*</span><span class="n">sighand</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">sigset_t</span>      <span class="n">blocked</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">sigset_t</span>      <span class="n">real_blocked</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">sigset_t</span>      <span class="n">saved_sigmask</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sigpending</span>    <span class="n">pending</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="kt">long</span>      <span class="n">sas_ss_sp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">size_t</span>        <span class="n">sas_ss_size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="kt">int</span>      <span class="n">sas_ss_flags</span><span class="p">;</span>
</span></span></code></pre></div><p>这里定义了哪些信号被阻塞暂不处理（blocked），哪些信号尚等待处理（pending），哪些信号正在通过信号处理函数进行处理（sighand）。处理的结果可以是忽略，可以是结束进程等等。</p>
<h3 id="任务状态">任务状态</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">volatile long state;    /* -1 unrunnable, 0 runnable, &gt;0 stopped */
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">int exit_state;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">unsigned int flags;
</span></span></code></pre></div><p><code>state</code>可取值定义如下</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* Used in tsk-&gt;state: */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define TASK_RUNNING                    0
</span></span></span><span class="line"><span class="cl"><span class="cp">#define TASK_INTERRUPTIBLE              1
</span></span></span><span class="line"><span class="cl"><span class="cp">#define TASK_UNINTERRUPTIBLE            2
</span></span></span><span class="line"><span class="cl"><span class="cp">#define __TASK_STOPPED                  4
</span></span></span><span class="line"><span class="cl"><span class="cp">#define __TASK_TRACED                   8
</span></span></span><span class="line"><span class="cl"><span class="cm">/* Used in tsk-&gt;exit_state: */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define EXIT_DEAD                       16
</span></span></span><span class="line"><span class="cl"><span class="cp">#define EXIT_ZOMBIE                     32
</span></span></span><span class="line"><span class="cl"><span class="cp">#define EXIT_TRACE                      (EXIT_ZOMBIE | EXIT_DEAD)
</span></span></span><span class="line"><span class="cl"><span class="cm">/* Used in tsk-&gt;state again: */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define TASK_DEAD                       64
</span></span></span><span class="line"><span class="cl"><span class="cp">#define TASK_WAKEKILL                   128
</span></span></span><span class="line"><span class="cl"><span class="cp">#define TASK_WAKING                     256
</span></span></span><span class="line"><span class="cl"><span class="cp">#define TASK_PARKED                     512
</span></span></span><span class="line"><span class="cl"><span class="cp">#define TASK_NOLOAD                     1024
</span></span></span><span class="line"><span class="cl"><span class="cp">#define TASK_NEW                        2048
</span></span></span><span class="line"><span class="cl"><span class="cp">#define TASK_STATE_MAX                  4096
</span></span></span></code></pre></div><p>可以发现 Linux 通过 bitset 方式设置状态，当前什么状态，哪一位就置 1。</p>
<h3 id="进程调度">进程调度</h3>
<p>进程的状态切换往往涉及调度，下面这些字段都是用于调度的。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 是否在运行队列上
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span>               <span class="n">on_rq</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 优先级
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span>               <span class="n">prio</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span>               <span class="n">static_prio</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span>               <span class="n">normal_prio</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="kt">int</span>      <span class="n">rt_priority</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 调度器类
</span></span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">struct</span> <span class="n">sched_class</span>  <span class="o">*</span><span class="n">sched_class</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 调度实体
</span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sched_entity</span>       <span class="n">se</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sched_rt_entity</span>    <span class="n">rt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sched_dl_entity</span>    <span class="n">dl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 调度策略
</span></span></span><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="kt">int</span>      <span class="n">policy</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="c1">// 可以使用哪些 CPU
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span>            <span class="n">nr_cpus_allowed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">cpumask_t</span>      <span class="n">cpus_allowed</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sched_info</span>    <span class="n">sched_info</span><span class="p">;</span>
</span></span></code></pre></div><h3 id="运行统计信息">运行统计信息</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="n">u64</span>        <span class="n">utime</span><span class="p">;</span><span class="c1">// 用户态消耗的 CPU 时间
</span></span></span><span class="line"><span class="cl"><span class="n">u64</span>        <span class="n">stime</span><span class="p">;</span><span class="c1">// 内核态消耗的 CPU 时间
</span></span></span><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="kt">long</span>      <span class="n">nvcsw</span><span class="p">;</span><span class="c1">// 自愿 (voluntary) 上下文切换计数
</span></span></span><span class="line"><span class="cl"><span class="kt">unsigned</span> <span class="kt">long</span>      <span class="n">nivcsw</span><span class="p">;</span><span class="c1">// 非自愿 (involuntary) 上下文切换计数
</span></span></span><span class="line"><span class="cl"><span class="n">u64</span>        <span class="n">start_time</span><span class="p">;</span><span class="c1">// 进程启动时间，不包含睡眠时间
</span></span></span><span class="line"><span class="cl"><span class="n">u64</span>        <span class="n">real_start_time</span><span class="p">;</span><span class="c1">// 进程启动时间，包含睡眠时间
</span></span></span></code></pre></div><h3 id="进程亲缘关系">进程亲缘关系</h3>
<p>进程有棵进程树，所以有亲缘关系。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">task_struct</span> <span class="n">__rcu</span> <span class="o">*</span><span class="n">real_parent</span><span class="p">;</span> <span class="cm">/* real parent process */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">task_struct</span> <span class="n">__rcu</span> <span class="o">*</span><span class="n">parent</span><span class="p">;</span> <span class="cm">/* recipient of SIGCHLD, wait4() reports */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">list_head</span> <span class="n">children</span><span class="p">;</span>      <span class="cm">/* list of my children */</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">list_head</span> <span class="n">sibling</span><span class="p">;</span>       <span class="cm">/* linkage in my parent&#39;s children list */</span>
</span></span></code></pre></div><p>通常情况下，<code>real_parent</code> 和 <code>parent</code> 是一样的，但是也会有另外的情况存在。例如，<code>bash</code> 创建一个进程，那进程的 parent 和 <code>real_parent</code> 就都是 <code>bash</code>。如果在 bash 上使用 <code>GDB</code> 来 <code>debug</code> 一个进程，这个时候 <code>GDB</code> 是 <code>real_parent</code>，<code>bash</code> 是这个进程的 <code>parent</code>。</p>
<h3 id="进程权限">进程权限</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* Objective and real subjective task credentials (COW): */</span>
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">struct</span> <span class="n">cred</span> <span class="n">__rcu</span>         <span class="o">*</span><span class="n">real_cred</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="cm">/* Effective (overridable) subjective task credentials (COW): */</span>
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">struct</span> <span class="n">cred</span> <span class="n">__rcu</span>   
</span></span></code></pre></div><p><code>real_cred</code> 就是说明谁能操作我这个进程，而 <code>cred</code> 就是说明我这个进程能够操作谁。</p>
<p>总结到一起，<code>task_struct</code>结构图如下，</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826190834.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826190834.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>CSAPPLAB-Bomb Lab</title>
      <link>https://lifeislife.cn/posts/csapp-lab-bomb-lab/</link>
      <pubDate>Sun, 29 Aug 2021 18:40:16 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/csapp-lab-bomb-lab/</guid>
      <description>&lt;h2 id=&#34;tips&#34;&gt;Tips&lt;/h2&gt;
&lt;h3 id=&#34;缩写注释&#34;&gt;缩写注释&lt;/h3&gt;
&lt;p&gt;CSAPP：Computer Systems A Programmer’s Perspective（深入理解计算机操作系统）。CSAPP（C：P166，O：P278）表示书本的中文版第 166 页，英文原版第 278 页。&lt;/p&gt;
&lt;h3 id=&#34;寄存器信息&#34;&gt;寄存器信息&lt;/h3&gt;
&lt;p&gt;了解寄存器的基本用途，看到一个汇编代码，可以大概了解这个寄存器是在栈中使用的，还是保存参数的，是调用者保存，还是被调用者保存。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830160500.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830160500.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div STYLE=&#34;page-break-after: always;&#34;&gt;&lt;/div&gt;
&lt;h3 id=&#34;gdb&#34;&gt;GDB&lt;/h3&gt;
&lt;p&gt;调试过程用到的 GDB 命令可以先参考&lt;a href=&#34;https://dunky-z.github.io/2021/08/29/GDB%E8%B0%83%E8%AF%95%E5%85%A5%E9%97%A8/&#34;&gt;GDB 调试入门&lt;/a&gt;这篇文章。文中所用例子也是摘自与 BombLab 的源码，更容易理解如何使用。还有一定比较重要的是，如何使用 gdb 带参数调试。为了不用每次运行&lt;code&gt;bomb&lt;/code&gt;程序都需要重新输入答案，&lt;code&gt;bomb&lt;/code&gt;程序可以读取文本信息，在文本文件中写入答案即可免去手动输入。&lt;/p&gt;
&lt;h2 id=&#34;phase_1&#34;&gt;phase_1&lt;/h2&gt;
&lt;p&gt;拆弹专家已上线，开干！！！！！！！！！！！！！&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) b phase_1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) b explode_bomb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas phase_1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function phase_1:&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ee0 &amp;lt;+0&amp;gt;: sub    $0x8,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ee4 &amp;lt;+4&amp;gt;: mov    $0x402400,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ee9 &amp;lt;+9&amp;gt;: callq  0x401338 &amp;lt;strings_not_equal&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400eee &amp;lt;+14&amp;gt;: test   %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ef0 &amp;lt;+16&amp;gt;: je     0x400ef7 &amp;lt;phase_1+23&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ef2 &amp;lt;+18&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ef7 &amp;lt;+23&amp;gt;: add    $0x8,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400efb &amp;lt;+27&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;3：将栈指针&lt;code&gt;rsp&lt;/code&gt;减去 8 个字节，也就是申请 8 个字节的栈空间&lt;/li&gt;
&lt;li&gt;4：将一个立即数存到寄存器&lt;code&gt;esi&lt;/code&gt;中&lt;/li&gt;
&lt;li&gt;5：调用函数&lt;code&gt;strings_not_equal&lt;/code&gt;，该函数第一条语句的地址为&lt;code&gt;0x401338&lt;/code&gt;。&lt;code&gt;callq&lt;/code&gt;指令的执行过程可参考书本 CSAPP（C：P166，O：P278）&lt;/li&gt;
&lt;li&gt;6：使用&lt;code&gt;test&lt;/code&gt;命令（同&lt;code&gt;and&lt;/code&gt;命令，不修改目标对象的值）来测试&lt;code&gt;eax&lt;/code&gt;中的值是否为&lt;code&gt;0&lt;/code&gt;，如果为&lt;code&gt;0&lt;/code&gt;则跳过引爆炸弹的函数&lt;/li&gt;
&lt;li&gt;7：这一句和上一句是一个整体，如果&lt;code&gt;eax==0&lt;/code&gt;,就跳转到&lt;code&gt;0x400ef7&lt;/code&gt;，这个地址也就是第 9 行的地址，成功跳过了引爆炸弹函数。意思就是我们输入的某个字符串成功匹配，也就是&lt;code&gt;strings_not_equal&lt;/code&gt;函数返回值为 0。&lt;/li&gt;
&lt;li&gt;8：调用函数&lt;code&gt;explode_bomb&lt;/code&gt;，引爆炸弹&lt;/li&gt;
&lt;li&gt;9：将栈指针&lt;code&gt;rsp&lt;/code&gt;加上 8 个字节，也就是恢复 8 个字节的栈空间&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas strings_not_equal 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function strings_not_equal:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;=&amp;gt; 0x0000000000401338 &amp;lt;+0&amp;gt;: push   %r12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040133a &amp;lt;+2&amp;gt;: push   %rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040133b &amp;lt;+3&amp;gt;: push   %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040133c &amp;lt;+4&amp;gt;: mov    %rdi,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040133f &amp;lt;+7&amp;gt;: mov    %rsi,%rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401342 &amp;lt;+10&amp;gt;: callq  0x40131b &amp;lt;string_length&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401347 &amp;lt;+15&amp;gt;: mov    %eax,%r12d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040134a &amp;lt;+18&amp;gt;: mov    %rbp,%rdi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040134d &amp;lt;+21&amp;gt;: callq  0x40131b &amp;lt;string_length&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401352 &amp;lt;+26&amp;gt;: mov    $0x1,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401357 &amp;lt;+31&amp;gt;: cmp    %eax,%r12d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040135a &amp;lt;+34&amp;gt;: jne    0x40139b &amp;lt;strings_not_equal+99&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040135c &amp;lt;+36&amp;gt;: movzbl (%rbx),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040135f &amp;lt;+39&amp;gt;: test   %al,%al
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401361 &amp;lt;+41&amp;gt;: je     0x401388 &amp;lt;strings_not_equal+80&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401363 &amp;lt;+43&amp;gt;: cmp    0x0(%rbp),%al
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401366 &amp;lt;+46&amp;gt;: je     0x401372 &amp;lt;strings_not_equal+58&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401368 &amp;lt;+48&amp;gt;: jmp    0x40138f &amp;lt;strings_not_equal+87&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040136a &amp;lt;+50&amp;gt;: cmp    0x0(%rbp),%al
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040136d &amp;lt;+53&amp;gt;: nopl   (%rax)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401370 &amp;lt;+56&amp;gt;: jne    0x401396 &amp;lt;strings_not_equal+94&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401372 &amp;lt;+58&amp;gt;: add    $0x1,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401376 &amp;lt;+62&amp;gt;: add    $0x1,%rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040137a &amp;lt;+66&amp;gt;: movzbl (%rbx),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040137d &amp;lt;+69&amp;gt;: test   %al,%al
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040137f &amp;lt;+71&amp;gt;: jne    0x40136a &amp;lt;strings_not_equal+50&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401381 &amp;lt;+73&amp;gt;: mov    $0x0,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401386 &amp;lt;+78&amp;gt;: jmp    0x40139b &amp;lt;strings_not_equal+99&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401388 &amp;lt;+80&amp;gt;: mov    $0x0,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040138d &amp;lt;+85&amp;gt;: jmp    0x40139b &amp;lt;strings_not_equal+99&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040138f &amp;lt;+87&amp;gt;: mov    $0x1,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401394 &amp;lt;+92&amp;gt;: jmp    0x40139b &amp;lt;strings_not_equal+99&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401396 &amp;lt;+94&amp;gt;: mov    $0x1,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040139b &amp;lt;+99&amp;gt;: mov    %edx,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040139d &amp;lt;+101&amp;gt;: pop    %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040139e &amp;lt;+102&amp;gt;: pop    %rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040139f &amp;lt;+103&amp;gt;: pop    %r12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004013a1 &amp;lt;+105&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;3-5：在函数调用时先保存相关寄存器值，&lt;code&gt;rbp&lt;/code&gt;和&lt;code&gt;rbx&lt;/code&gt;就是用来保存两个参数的寄存器&lt;/li&gt;
&lt;li&gt;6：将寄存器&lt;code&gt;rdi&lt;/code&gt;的值复制到寄存器&lt;code&gt;rbp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;7：将寄存器&lt;code&gt;rsi&lt;/code&gt;的值复制到寄存器&lt;code&gt;rbx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其实看到这里就一直能够猜到答案是什么了。我们通过之前的&lt;code&gt;phase_1&lt;/code&gt;函数能够大概知道需要输入一个值进行比较，如果比较正确就能解除炸弹。现在我们又进入到了这个比较函数，比较函数有两个参数，分别保存在两个寄存器里。我们正常的思维如果写一个比较函数，肯定一个参数是我们输入的值，一个参数是正确的值。&lt;/p&gt;
&lt;p&gt;这里看到了&lt;code&gt;rsi&lt;/code&gt;寄存器，我们还记得在&lt;code&gt;phase_1&lt;/code&gt;函数中第 4 行的&lt;code&gt;esi&lt;/code&gt;寄存器吗？这两个寄存器是同一个寄存器，只不过&lt;code&gt;esi&lt;/code&gt;是寄存器的低 32 位，既然&lt;code&gt;esi&lt;/code&gt;已经赋值了，那剩下的一个参数保存我们输入的内容。所以&lt;code&gt;esi&lt;/code&gt;内存的内容就是我们需要的正确答案。我们只要把寄存器&lt;code&gt;esi&lt;/code&gt;中的值打印出来，或者内存地址为&lt;code&gt;0x402400&lt;/code&gt;的内容打印出来即可。可以通过以下三条命令查看。&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p (char*)($esi)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$5 = 0x402400 &amp;#34;Border relations with Canada have never been better.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) x/s 0x402400
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x402400: &amp;#34;Border relations with Canada have never been better.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) x/s $esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x402400: &amp;#34;Border relations with Canada have never been better.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将答案复制，然后继续运行&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The program being debugged has been started already.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Start it from the beginning? (y or n) y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Starting program: /home/dominic/learning-linux/bomb/bomb 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Welcome to my fiendish little bomb. You have 6 phases with
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which to blow yourself up. Have a nice day!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Border relations with Canada have never been better.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 2, 0x0000000000400ee0 in phase_1 ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Single stepping until exit from function phase_1,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which has no line number information.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;main (argc=&amp;lt;optimized out&amp;gt;, argv=&amp;lt;optimized out&amp;gt;) at bomb.c:75
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;75     phase_defused();                 /* Drat!  They figured it out!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;77     printf(&amp;#34;Phase 1 defused. How about the next one?\n&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从 13 行&lt;code&gt;phase_defused()&lt;/code&gt;可以知道我们已经解除了炸弹，从 15 行&lt;code&gt;printf&lt;/code&gt;函数也可以看到，需要进行下一个炸弹的拆除。过来人的建议，在这里就开始分析&lt;code&gt;phase_2&lt;/code&gt;，寻找答案，因为继续执行就要开始输入内容了，将无法调试。&lt;/p&gt;
&lt;h2 id=&#34;phase_2&#34;&gt;phase_2&lt;/h2&gt;
&lt;p&gt;继续分析第二个炸弹，&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas phase_2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function phase_2:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400efc &amp;lt;+0&amp;gt;: push   %rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400efd &amp;lt;+1&amp;gt;: push   %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400efe &amp;lt;+2&amp;gt;: sub    $0x28,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f02 &amp;lt;+6&amp;gt;: mov    %rsp,%rsi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f05 &amp;lt;+9&amp;gt;: callq  0x40145c &amp;lt;read_six_numbers&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f0a &amp;lt;+14&amp;gt;: cmpl   $0x1,(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f0e &amp;lt;+18&amp;gt;: je     0x400f30 &amp;lt;phase_2+52&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f10 &amp;lt;+20&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f15 &amp;lt;+25&amp;gt;: jmp    0x400f30 &amp;lt;phase_2+52&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f17 &amp;lt;+27&amp;gt;: mov    -0x4(%rbx),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f1a &amp;lt;+30&amp;gt;: add    %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f1c &amp;lt;+32&amp;gt;: cmp    %eax,(%rbx)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f1e &amp;lt;+34&amp;gt;: je     0x400f25 &amp;lt;phase_2+41&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f20 &amp;lt;+36&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f25 &amp;lt;+41&amp;gt;: add    $0x4,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f29 &amp;lt;+45&amp;gt;: cmp    %rbp,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f2c &amp;lt;+48&amp;gt;: jne    0x400f17 &amp;lt;phase_2+27&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f2e &amp;lt;+50&amp;gt;: jmp    0x400f3c &amp;lt;phase_2+64&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f30 &amp;lt;+52&amp;gt;: lea    0x4(%rsp),%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f35 &amp;lt;+57&amp;gt;: lea    0x18(%rsp),%rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f3a &amp;lt;+62&amp;gt;: jmp    0x400f17 &amp;lt;phase_2+27&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f3c &amp;lt;+64&amp;gt;: add    $0x28,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f40 &amp;lt;+68&amp;gt;: pop    %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f41 &amp;lt;+69&amp;gt;: pop    %rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f42 &amp;lt;+70&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;3-6：保存程序入口地址，变量等内容，就不再赘述了&lt;/li&gt;
&lt;li&gt;7: 调用&lt;code&gt;read_six_numbers&lt;/code&gt;函数，根据函数名我们可以猜测这个函数需要读入六个数字&lt;/li&gt;
&lt;li&gt;8-9：比较寄存器&lt;code&gt;rsp&lt;/code&gt;存的第一个数字是否等于&lt;code&gt;0x1&lt;/code&gt;，如果等于就跳转到&lt;code&gt;phase_2+52&lt;/code&gt;处继续执行，如果不等于就执行&lt;code&gt;explode_bomb&lt;/code&gt;。栈中保存了六个输入的数字，保存顺序是从右往左，假如输入&lt;code&gt;1,2,3,4,5,6&lt;/code&gt;。那么入栈的顺序就是&lt;code&gt;6,5,4,3,2,1&lt;/code&gt;，寄存器&lt;code&gt;rsp&lt;/code&gt;指向栈顶，也就是数字&lt;code&gt;1&lt;/code&gt;的地址。&lt;/li&gt;
&lt;li&gt;21:假设第一个数字正确，我们跳转到&lt;code&gt;&amp;lt;+52&amp;gt;&lt;/code&gt;位置，也就是第 21 行，将&lt;code&gt;rsp+0x4&lt;/code&gt;写入寄存器&lt;code&gt;rbx&lt;/code&gt;，栈指针向上移动四个字节，也就是取第二个输入的参数，将它赋给寄存器&lt;code&gt;rbx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;22：将&lt;code&gt;rsp+0x18&lt;/code&gt;写入寄存器&lt;code&gt;rbp&lt;/code&gt;，十六进制&lt;code&gt;0x18=24&lt;/code&gt;，4 个字节一个数，刚好 6 个数，就是将输入参数的最后一个位置赋给寄存器&lt;code&gt;rbp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;23：跳到&lt;code&gt;phase_2+27&lt;/code&gt;继续执行&lt;/li&gt;
&lt;li&gt;12：&lt;code&gt;rbx-0x4&lt;/code&gt;赋给寄存器&lt;code&gt;eax&lt;/code&gt;。第 21 行我们知道，&lt;code&gt;rbx&lt;/code&gt;此时已经到第二个参数了，这一句就是说把第一个参数的值写入寄存器&lt;code&gt;eax&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;13：将&lt;code&gt;eax&lt;/code&gt;翻一倍，第 8 行知道第一个参数值为&lt;code&gt;1&lt;/code&gt;，所以此时&lt;code&gt;eax&lt;/code&gt;值为&lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;14-15：比较&lt;code&gt;eax&lt;/code&gt;是否等于&lt;code&gt;rbx&lt;/code&gt;。&lt;code&gt;rbx&lt;/code&gt;此时保存的是第二个参数，这里也就是比较第二个参数是否等于&lt;code&gt;2&lt;/code&gt;。如果等于跳转到&lt;code&gt;phase_2+41&lt;/code&gt;位置，如果不等于就调用爆炸函数&lt;/li&gt;
&lt;li&gt;17-18：假设第二个参数就是 2，我们跳过了炸弹来到第 17 行，将&lt;code&gt;rbx&lt;/code&gt;继续上移，然后比较&lt;code&gt;rbp&lt;/code&gt;是否等于&lt;code&gt;rbx&lt;/code&gt;，我们知道&lt;code&gt;rbp&lt;/code&gt;保存了最后一个参数的地址，所以这里的意思就是看看参数有没有到最后一个参数。&lt;/li&gt;
&lt;li&gt;19：如果&lt;code&gt;rbx&amp;lt;rbp&lt;/code&gt;，意思就是还没到最后一个参数，就跳转到&lt;code&gt;phase_2+27&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;12：再次回到第 12 行，这里就是相当于一个循环了，让&lt;code&gt;rbx&lt;/code&gt;一直向上移动，分别存入第 2，3，4，5，6 个参数，在移动到下一个参数时先保存当前参数到寄存器&lt;code&gt;eax&lt;/code&gt;让其翻一倍，然后&lt;code&gt;rbx&lt;/code&gt;再移动到下一个参数，比较&lt;code&gt;eax==rbx&lt;/code&gt;。直到&lt;code&gt;rbx&lt;/code&gt;越过了&lt;code&gt;rbp&lt;/code&gt;。程序跳转到&lt;code&gt;phase_2+64&lt;/code&gt;，将栈空间恢复。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上分析也可以得出答案了，我们只要输入一个以&lt;code&gt;1&lt;/code&gt;为初值，公比为&lt;code&gt;2&lt;/code&gt;，个数为&lt;code&gt;6&lt;/code&gt;的等比数列就是答案，也就是&lt;code&gt;1 2 4 8 16 32&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Continuing.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Phase &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; defused. How about the next one?
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 6, 0x00000000004015c4 in phase_defused &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Single stepping &lt;span class=&#34;k&#34;&gt;until&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; from &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; phase_defused,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which has no line number information.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;main &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&amp;lt;optimized out&amp;gt;, &lt;span class=&#34;nv&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&amp;lt;optimized out&amp;gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; at bomb.c:84
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt;     printf&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;That&amp;#39;s number 2.  Keep going!\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个炸弹的作者应该再心狠手辣一点，把函数名换成&lt;code&gt;read_some_numbers&lt;/code&gt;，这样我们就不得不看这个函数的内容了，因为这个函数里还有一个坑，这个坑在函数名字上一句被填了。那就是这个函数会对参数个数做判断，如果小于 5 就爆炸。&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas read_six_numbers
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function read_six_numbers:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040145c &amp;lt;+0&amp;gt;: sub    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401460 &amp;lt;+4&amp;gt;: mov    %rsi,%rdx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401463 &amp;lt;+7&amp;gt;: lea    0x4(%rsi),%rcx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401467 &amp;lt;+11&amp;gt;: lea    0x14(%rsi),%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040146b &amp;lt;+15&amp;gt;: mov    %rax,0x8(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401470 &amp;lt;+20&amp;gt;: lea    0x10(%rsi),%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401474 &amp;lt;+24&amp;gt;: mov    %rax,(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401478 &amp;lt;+28&amp;gt;: lea    0xc(%rsi),%r9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040147c &amp;lt;+32&amp;gt;: lea    0x8(%rsi),%r8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401480 &amp;lt;+36&amp;gt;: mov    $0x4025c3,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401485 &amp;lt;+41&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040148a &amp;lt;+46&amp;gt;: callq  0x400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040148f &amp;lt;+51&amp;gt;: cmp    $0x5,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401492 &amp;lt;+54&amp;gt;: jg     0x401499 &amp;lt;read_six_numbers+61&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401494 &amp;lt;+56&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401499 &amp;lt;+61&amp;gt;: add    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040149d &amp;lt;+65&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;3：申请 24 个字节栈空间&lt;/li&gt;
&lt;li&gt;4：&lt;code&gt;rdx=rsi&lt;/code&gt;，将输入参数的第一个参数放到寄存器&lt;code&gt;rdx&lt;/code&gt;中，为啥是第一个参数，因为&lt;code&gt;rsi&lt;/code&gt;现在保存的地址是栈顶位置，栈顶目前保存就是第一个参数。&lt;/li&gt;
&lt;li&gt;5：&lt;code&gt;rcx = rsi + 4&lt;/code&gt;，把第二个参数的地址传给寄存器&lt;code&gt;rcx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;6：&lt;code&gt;rax = rsi + 20&lt;/code&gt;，把第六个参数的地址传给寄存器&lt;code&gt;rax&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;7：&lt;code&gt;rsp + 8 = rax&lt;/code&gt;第八个参数&lt;/li&gt;
&lt;li&gt;8：&lt;code&gt;rax = rsi + 16&lt;/code&gt;，把第五个参数传给&lt;/li&gt;
&lt;li&gt;9：&lt;code&gt;rsp = rax&lt;/code&gt;第七个参数&lt;/li&gt;
&lt;li&gt;10：&lt;code&gt;r9 = rsi + 12&lt;/code&gt;把第四个参数传给寄存器&lt;code&gt;r9&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;11：&lt;code&gt;r8 = rsi + 8&lt;/code&gt;把第三个参数传给寄存器&lt;code&gt;r8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;12：&lt;/li&gt;
&lt;li&gt;13：&lt;code&gt;eax = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;14：调用输入函数&lt;code&gt;sscanf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;15-17：函数返回值个数与 5 比较，如果小于 5 就爆炸，否则返回&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;phase_3&#34;&gt;phase_3&lt;/h2&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f43 &amp;lt;+0&amp;gt;: sub    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f47 &amp;lt;+4&amp;gt;: lea    0xc(%rsp),%rcx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f4c &amp;lt;+9&amp;gt;: lea    0x8(%rsp),%rdx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f51 &amp;lt;+14&amp;gt;: mov    $0x4025cf,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f56 &amp;lt;+19&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f5b &amp;lt;+24&amp;gt;: callq  0x400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f60 &amp;lt;+29&amp;gt;: cmp    $0x1,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f63 &amp;lt;+32&amp;gt;: jg     0x400f6a &amp;lt;phase_3+39&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f65 &amp;lt;+34&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f6a &amp;lt;+39&amp;gt;: cmpl   $0x7,0x8(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f6f &amp;lt;+44&amp;gt;: ja     0x400fad &amp;lt;phase_3+106&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f71 &amp;lt;+46&amp;gt;: mov    0x8(%rsp),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f75 &amp;lt;+50&amp;gt;: jmpq   *0x402470(,%rax,8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f7c &amp;lt;+57&amp;gt;: mov    $0xcf,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f81 &amp;lt;+62&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f83 &amp;lt;+64&amp;gt;: mov    $0x2c3,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f88 &amp;lt;+69&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f8a &amp;lt;+71&amp;gt;: mov    $0x100,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f8f &amp;lt;+76&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f91 &amp;lt;+78&amp;gt;: mov    $0x185,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f96 &amp;lt;+83&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f98 &amp;lt;+85&amp;gt;: mov    $0xce,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f9d &amp;lt;+90&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f9f &amp;lt;+92&amp;gt;: mov    $0x2aa,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fa4 &amp;lt;+97&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fa6 &amp;lt;+99&amp;gt;: mov    $0x147,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fab &amp;lt;+104&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fad &amp;lt;+106&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fb2 &amp;lt;+111&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fb7 &amp;lt;+116&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fb9 &amp;lt;+118&amp;gt;: mov    $0x137,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fbe &amp;lt;+123&amp;gt;: cmp    0xc(%rsp),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fc2 &amp;lt;+127&amp;gt;: je     0x400fc9 &amp;lt;phase_3+134&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fc4 &amp;lt;+129&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fc9 &amp;lt;+134&amp;gt;: add    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fcd &amp;lt;+138&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;1：开辟 24 字节的栈空间&lt;/li&gt;
&lt;li&gt;2：&lt;code&gt;rcx = rsp + 12&lt;/code&gt;第二个参数&lt;/li&gt;
&lt;li&gt;3：&lt;code&gt;rdx = rsp + 8&lt;/code&gt;第一个参数&lt;/li&gt;
&lt;li&gt;4-8：和&lt;code&gt;phase_2&lt;/code&gt;里&lt;code&gt;read_six_numbers&lt;/code&gt;函数中的第 13 行开始一样，输入数据，判断一下输入参数的个数，只不过这里是返回值个数大于 1，如果参数个数正确就跳到&lt;code&gt;phase_3+39&lt;/code&gt;也就是第 10 行，否则引爆炸弹。&lt;/li&gt;
&lt;li&gt;10-11：如果&lt;code&gt;7 &amp;lt; rsp + 8 等价于 7 &amp;lt; rdx 等价于 7 &amp;lt; 第一个参数&lt;/code&gt;就跳转到&lt;code&gt;phase_3+106&lt;/code&gt;，爆炸。这里确定第一个数必须小于 7&lt;/li&gt;
&lt;li&gt;12：&lt;code&gt;eax = rsp + 8 等价于 eax = 第一个参数&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;13：跳转至&lt;code&gt;0x402470 + 8 * rax&lt;/code&gt;处，具体跳转到哪里根据第一个值做判断&lt;/li&gt;
&lt;li&gt;14：&lt;code&gt;eax = 207&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;15：跳转至&lt;code&gt;phase_3+123&lt;/code&gt;,即 32 行&lt;/li&gt;
&lt;li&gt;16：&lt;code&gt;eax = 707&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;17：跳转到 32 行&lt;/li&gt;
&lt;li&gt;18：&lt;code&gt;eax = 256&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;19：跳转到 32 行&lt;/li&gt;
&lt;li&gt;20：&lt;code&gt;eax = 389&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;21-27：以此类推&lt;/li&gt;
&lt;li&gt;29：&lt;code&gt;eax = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;30：&lt;/li&gt;
&lt;li&gt;31：&lt;code&gt;eax = 311&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;32-34：比较&lt;code&gt;eax&lt;/code&gt;和&lt;code&gt;rsp + 12&lt;/code&gt; 等价于 比较 第二个参数和&lt;code&gt;eax&lt;/code&gt;。如果相等就返回，如果不等就引爆。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;分析至此，我们也就知道了程序的大概流程，输入两个值，第一个值必须小于等于 7，第二个值根据第一个值来确定，具体等于多少，根据跳转表确定，因为第一个值有八个数，也就对应着汇编中八段寄存器&lt;code&gt;eax&lt;/code&gt;赋值的过程，我们只要输入第一个合法的数值，然后再打印出寄存器&lt;code&gt;eax&lt;/code&gt;的值，即可确定答案。&lt;/p&gt;
&lt;p&gt;比如我们先测试一下第一个值为 0 时，对应的第二个值为多少，我们输入&lt;code&gt;0  10&lt;/code&gt;，因为只是测试，第二个值任意。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;That&amp;#39;s number 2.  Keep going! //接上个炸弹后面
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;88     input = read_line();
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 10              //输入测试答案
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;89     phase_3(input);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 4, 0x0000000000400f43 in phase_3 ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Single stepping until exit from function phase_3,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which has no line number information.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 2, 0x000000000040143a in explode_bomb ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p $eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$14 = 207         //207即是答案
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输入真正答案测试，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 207                         //输入答案
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;89     phase_3(input);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 4, 0x0000000000400f43 in phase_3 ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Single stepping until exit from function phase_3,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which has no line number information.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;main (argc=&amp;lt;optimized out&amp;gt;, argv=&amp;lt;optimized out&amp;gt;) at bomb.c:90
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;90     phase_defused();    //炸弹拆除
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;91     printf(&amp;#34;Halfway there!\n&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们上面说过，第一个值有八种可能，所以这题答案也有八个，我们只要挨个测试&lt;code&gt;0-7&lt;/code&gt;，分别打印出寄存器&lt;code&gt;eax&lt;/code&gt;的值就可以得到所有答案。他们分别是&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 207
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1 311
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 707
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3 256
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4 389
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5 206
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6 682
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;7 327
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;phase_4&#34;&gt;phase_4&lt;/h2&gt;
&lt;p&gt;行百里者半九十，NO&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas phase_4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function phase_4:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040100c &amp;lt;+0&amp;gt;: sub    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401010 &amp;lt;+4&amp;gt;: lea    0xc(%rsp),%rcx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401015 &amp;lt;+9&amp;gt;: lea    0x8(%rsp),%rdx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040101a &amp;lt;+14&amp;gt;: mov    $0x4025cf,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040101f &amp;lt;+19&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401024 &amp;lt;+24&amp;gt;: callq  0x400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401029 &amp;lt;+29&amp;gt;: cmp    $0x2,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040102c &amp;lt;+32&amp;gt;: jne    0x401035 &amp;lt;phase_4+41&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040102e &amp;lt;+34&amp;gt;: cmpl   $0xe,0x8(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401033 &amp;lt;+39&amp;gt;: jbe    0x40103a &amp;lt;phase_4+46&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401035 &amp;lt;+41&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040103a &amp;lt;+46&amp;gt;: mov    $0xe,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040103f &amp;lt;+51&amp;gt;: mov    $0x0,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401044 &amp;lt;+56&amp;gt;: mov    0x8(%rsp),%edi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401048 &amp;lt;+60&amp;gt;: callq  0x400fce &amp;lt;func4&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040104d &amp;lt;+65&amp;gt;: test   %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040104f &amp;lt;+67&amp;gt;: jne    0x401058 &amp;lt;phase_4+76&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401051 &amp;lt;+69&amp;gt;: cmpl   $0x0,0xc(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401056 &amp;lt;+74&amp;gt;: je     0x40105d &amp;lt;phase_4+81&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401058 &amp;lt;+76&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040105d &amp;lt;+81&amp;gt;: add    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401061 &amp;lt;+85&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;1-8：开辟空间，保存参数信息，调用输入函数，和上面的分析重复，不再赘述。注意的是第 6 行，&lt;code&gt;x/s 0x4025cf&lt;/code&gt;可知两个参数是整型数值。&lt;/li&gt;
&lt;li&gt;9-10：参数个数必须等于 2，否则引爆&lt;/li&gt;
&lt;li&gt;11-12：&lt;code&gt;14&lt;/code&gt;与&lt;code&gt;rsp + 8&lt;/code&gt;比较，等价于&lt;code&gt;14&lt;/code&gt;与第一个参数比较。表示第一个参数必须小于等于 14，否则引爆。&lt;/li&gt;
&lt;li&gt;14：&lt;code&gt;edx = 14&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;15：&lt;code&gt;esi = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;16：&lt;code&gt;edi = rsp + 8&lt;/code&gt;即&lt;code&gt;edi = 第一个参数&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;17：调用函数&lt;code&gt;fun4&lt;/code&gt;，参数分别为&lt;code&gt;edi 0 14&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;18：测试返回值是否为 0，如果不为 0，引爆&lt;/li&gt;
&lt;li&gt;20-22：比较&lt;code&gt;0&lt;/code&gt;和&lt;code&gt;rsp + 12&lt;/code&gt;，如果不等，引爆，否则返回&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas func4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function func4:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fce &amp;lt;+0&amp;gt;: sub    $0x8,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fd2 &amp;lt;+4&amp;gt;: mov    %edx,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fd4 &amp;lt;+6&amp;gt;: sub    %esi,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fd6 &amp;lt;+8&amp;gt;: mov    %eax,%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fd8 &amp;lt;+10&amp;gt;: shr    $0x1f,%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fdb &amp;lt;+13&amp;gt;: add    %ecx,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fdd &amp;lt;+15&amp;gt;: sar    %eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fdf &amp;lt;+17&amp;gt;: lea    (%rax,%rsi,1),%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fe2 &amp;lt;+20&amp;gt;: cmp    %edi,%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fe4 &amp;lt;+22&amp;gt;: jle    0x400ff2 &amp;lt;func4+36&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fe6 &amp;lt;+24&amp;gt;: lea    -0x1(%rcx),%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fe9 &amp;lt;+27&amp;gt;: callq  0x400fce &amp;lt;func4&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fee &amp;lt;+32&amp;gt;: add    %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ff0 &amp;lt;+34&amp;gt;: jmp    0x401007 &amp;lt;func4+57&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ff2 &amp;lt;+36&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ff7 &amp;lt;+41&amp;gt;: cmp    %edi,%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ff9 &amp;lt;+43&amp;gt;: jge    0x401007 &amp;lt;func4+57&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ffb &amp;lt;+45&amp;gt;: lea    0x1(%rcx),%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ffe &amp;lt;+48&amp;gt;: callq  0x400fce &amp;lt;func4&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401003 &amp;lt;+53&amp;gt;: lea    0x1(%rax,%rax,1),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401007 &amp;lt;+57&amp;gt;: add    $0x8,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040100b &amp;lt;+61&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;c1&#34;&gt;// edi = 第一个参数, esi = 0, edx = 14
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// 4:mov %edx, %eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 5:sub esi, %eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// 6:mov %eax, %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eсx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;// 7:shr  $0x1f, %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;// 8:add %ecx, %eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//替换eax和ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 9:sar %eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// 10:lea (rax,ersi,1), %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;c1&#34;&gt;// 11:cmp %edi, %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// 12:jle 400ff2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// mov $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// 18:cmp %edi, %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;c1&#34;&gt;// 19:jge    0x401007 &amp;lt;func4+57&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;c1&#34;&gt;//由此可以得知道 edx == edi
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;phase_5&#34;&gt;phase_5&lt;/h2&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401062 &amp;lt;+0&amp;gt;: push   %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401063 &amp;lt;+1&amp;gt;: sub    $0x20,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401067 &amp;lt;+5&amp;gt;: mov    %rdi,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040106a &amp;lt;+8&amp;gt;: mov    %fs:0x28,%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401073 &amp;lt;+17&amp;gt;: mov    %rax,0x18(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401078 &amp;lt;+22&amp;gt;: xor    %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040107a &amp;lt;+24&amp;gt;: callq  0x40131b &amp;lt;string_length&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040107f &amp;lt;+29&amp;gt;: cmp    $0x6,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401082 &amp;lt;+32&amp;gt;: je     0x4010d2 &amp;lt;phase_5+112&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401084 &amp;lt;+34&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401089 &amp;lt;+39&amp;gt;: jmp    0x4010d2 &amp;lt;phase_5+112&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040108b &amp;lt;+41&amp;gt;: movzbl (%rbx,%rax,1),%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040108f &amp;lt;+45&amp;gt;: mov    %cl,(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401092 &amp;lt;+48&amp;gt;: mov    (%rsp),%rdx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401096 &amp;lt;+52&amp;gt;: and    $0xf,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401099 &amp;lt;+55&amp;gt;: movzbl 0x4024b0(%rdx),%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010a0 &amp;lt;+62&amp;gt;: mov    %dl,0x10(%rsp,%rax,1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010a4 &amp;lt;+66&amp;gt;: add    $0x1,%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010a8 &amp;lt;+70&amp;gt;: cmp    $0x6,%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010ac &amp;lt;+74&amp;gt;: jne    0x40108b &amp;lt;phase_5+41&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010ae &amp;lt;+76&amp;gt;: movb   $0x0,0x16(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010b3 &amp;lt;+81&amp;gt;: mov    $0x40245e,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      0x00000000004010b8 &amp;lt;+86&amp;gt;: lea    0x10(%rsp),%rdi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010bd &amp;lt;+91&amp;gt;: callq  0x401338 &amp;lt;strings_not_equal&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010c2 &amp;lt;+96&amp;gt;: test   %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010c4 &amp;lt;+98&amp;gt;: je     0x4010d9 &amp;lt;phase_5+119&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010c6 &amp;lt;+100&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010cb &amp;lt;+105&amp;gt;: nopl   0x0(%rax,%rax,1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010d0 &amp;lt;+110&amp;gt;: jmp    0x4010d9 &amp;lt;phase_5+119&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010d2 &amp;lt;+112&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010d7 &amp;lt;+117&amp;gt;: jmp    0x40108b &amp;lt;phase_5+41&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010d9 &amp;lt;+119&amp;gt;: mov    0x18(%rsp),%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010de &amp;lt;+124&amp;gt;: xor    %fs:0x28,%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010e7 &amp;lt;+133&amp;gt;: je     0x4010ee &amp;lt;phase_5+140&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010e9 &amp;lt;+135&amp;gt;: callq  0x400b30 &amp;lt;__stack_chk_fail@plt&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010ee &amp;lt;+140&amp;gt;: add    $0x20,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010f2 &amp;lt;+144&amp;gt;: pop    %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010f3 &amp;lt;+145&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="tips">Tips</h2>
<h3 id="缩写注释">缩写注释</h3>
<p>CSAPP：Computer Systems A Programmer’s Perspective（深入理解计算机操作系统）。CSAPP（C：P166，O：P278）表示书本的中文版第 166 页，英文原版第 278 页。</p>
<h3 id="寄存器信息">寄存器信息</h3>
<p>了解寄存器的基本用途，看到一个汇编代码，可以大概了解这个寄存器是在栈中使用的，还是保存参数的，是调用者保存，还是被调用者保存。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830160500.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830160500.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div STYLE="page-break-after: always;"></div>
<h3 id="gdb">GDB</h3>
<p>调试过程用到的 GDB 命令可以先参考<a href="https://dunky-z.github.io/2021/08/29/GDB%E8%B0%83%E8%AF%95%E5%85%A5%E9%97%A8/">GDB 调试入门</a>这篇文章。文中所用例子也是摘自与 BombLab 的源码，更容易理解如何使用。还有一定比较重要的是，如何使用 gdb 带参数调试。为了不用每次运行<code>bomb</code>程序都需要重新输入答案，<code>bomb</code>程序可以读取文本信息，在文本文件中写入答案即可免去手动输入。</p>
<h2 id="phase_1">phase_1</h2>
<p>拆弹专家已上线，开干！！！！！！！！！！！！！</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">(gdb) b phase_1
</span></span><span class="line"><span class="cl">(gdb) b explode_bomb
</span></span><span class="line"><span class="cl">(gdb) disas phase_1
</span></span><span class="line"><span class="cl">Dump of assembler code for function phase_1:&#39;
</span></span><span class="line"><span class="cl">   0x0000000000400ee0 &lt;+0&gt;: sub    $0x8,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400ee4 &lt;+4&gt;: mov    $0x402400,%esi
</span></span><span class="line"><span class="cl">   0x0000000000400ee9 &lt;+9&gt;: callq  0x401338 &lt;strings_not_equal&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400eee &lt;+14&gt;: test   %eax,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400ef0 &lt;+16&gt;: je     0x400ef7 &lt;phase_1+23&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400ef2 &lt;+18&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400ef7 &lt;+23&gt;: add    $0x8,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400efb &lt;+27&gt;: retq   
</span></span><span class="line"><span class="cl">End of assembler dump.
</span></span></code></pre></div><ul>
<li>3：将栈指针<code>rsp</code>减去 8 个字节，也就是申请 8 个字节的栈空间</li>
<li>4：将一个立即数存到寄存器<code>esi</code>中</li>
<li>5：调用函数<code>strings_not_equal</code>，该函数第一条语句的地址为<code>0x401338</code>。<code>callq</code>指令的执行过程可参考书本 CSAPP（C：P166，O：P278）</li>
<li>6：使用<code>test</code>命令（同<code>and</code>命令，不修改目标对象的值）来测试<code>eax</code>中的值是否为<code>0</code>，如果为<code>0</code>则跳过引爆炸弹的函数</li>
<li>7：这一句和上一句是一个整体，如果<code>eax==0</code>,就跳转到<code>0x400ef7</code>，这个地址也就是第 9 行的地址，成功跳过了引爆炸弹函数。意思就是我们输入的某个字符串成功匹配，也就是<code>strings_not_equal</code>函数返回值为 0。</li>
<li>8：调用函数<code>explode_bomb</code>，引爆炸弹</li>
<li>9：将栈指针<code>rsp</code>加上 8 个字节，也就是恢复 8 个字节的栈空间</li>
</ul>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas strings_not_equal 
</span></span><span class="line"><span class="cl">Dump of assembler code for function strings_not_equal:
</span></span><span class="line"><span class="cl">=&gt; 0x0000000000401338 &lt;+0&gt;: push   %r12
</span></span><span class="line"><span class="cl">   0x000000000040133a &lt;+2&gt;: push   %rbp
</span></span><span class="line"><span class="cl">   0x000000000040133b &lt;+3&gt;: push   %rbx
</span></span><span class="line"><span class="cl">   0x000000000040133c &lt;+4&gt;: mov    %rdi,%rbx
</span></span><span class="line"><span class="cl">   0x000000000040133f &lt;+7&gt;: mov    %rsi,%rbp
</span></span><span class="line"><span class="cl">   0x0000000000401342 &lt;+10&gt;: callq  0x40131b &lt;string_length&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401347 &lt;+15&gt;: mov    %eax,%r12d
</span></span><span class="line"><span class="cl">   0x000000000040134a &lt;+18&gt;: mov    %rbp,%rdi
</span></span><span class="line"><span class="cl">   0x000000000040134d &lt;+21&gt;: callq  0x40131b &lt;string_length&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401352 &lt;+26&gt;: mov    $0x1,%edx
</span></span><span class="line"><span class="cl">   0x0000000000401357 &lt;+31&gt;: cmp    %eax,%r12d
</span></span><span class="line"><span class="cl">   0x000000000040135a &lt;+34&gt;: jne    0x40139b &lt;strings_not_equal+99&gt;
</span></span><span class="line"><span class="cl">   0x000000000040135c &lt;+36&gt;: movzbl (%rbx),%eax
</span></span><span class="line"><span class="cl">   0x000000000040135f &lt;+39&gt;: test   %al,%al
</span></span><span class="line"><span class="cl">   0x0000000000401361 &lt;+41&gt;: je     0x401388 &lt;strings_not_equal+80&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401363 &lt;+43&gt;: cmp    0x0(%rbp),%al
</span></span><span class="line"><span class="cl">   0x0000000000401366 &lt;+46&gt;: je     0x401372 &lt;strings_not_equal+58&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401368 &lt;+48&gt;: jmp    0x40138f &lt;strings_not_equal+87&gt;
</span></span><span class="line"><span class="cl">   0x000000000040136a &lt;+50&gt;: cmp    0x0(%rbp),%al
</span></span><span class="line"><span class="cl">   0x000000000040136d &lt;+53&gt;: nopl   (%rax)
</span></span><span class="line"><span class="cl">   0x0000000000401370 &lt;+56&gt;: jne    0x401396 &lt;strings_not_equal+94&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401372 &lt;+58&gt;: add    $0x1,%rbx
</span></span><span class="line"><span class="cl">   0x0000000000401376 &lt;+62&gt;: add    $0x1,%rbp
</span></span><span class="line"><span class="cl">   0x000000000040137a &lt;+66&gt;: movzbl (%rbx),%eax
</span></span><span class="line"><span class="cl">   0x000000000040137d &lt;+69&gt;: test   %al,%al
</span></span><span class="line"><span class="cl">   0x000000000040137f &lt;+71&gt;: jne    0x40136a &lt;strings_not_equal+50&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401381 &lt;+73&gt;: mov    $0x0,%edx
</span></span><span class="line"><span class="cl">   0x0000000000401386 &lt;+78&gt;: jmp    0x40139b &lt;strings_not_equal+99&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401388 &lt;+80&gt;: mov    $0x0,%edx
</span></span><span class="line"><span class="cl">   0x000000000040138d &lt;+85&gt;: jmp    0x40139b &lt;strings_not_equal+99&gt;
</span></span><span class="line"><span class="cl">   0x000000000040138f &lt;+87&gt;: mov    $0x1,%edx
</span></span><span class="line"><span class="cl">   0x0000000000401394 &lt;+92&gt;: jmp    0x40139b &lt;strings_not_equal+99&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401396 &lt;+94&gt;: mov    $0x1,%edx
</span></span><span class="line"><span class="cl">   0x000000000040139b &lt;+99&gt;: mov    %edx,%eax
</span></span><span class="line"><span class="cl">   0x000000000040139d &lt;+101&gt;: pop    %rbx
</span></span><span class="line"><span class="cl">   0x000000000040139e &lt;+102&gt;: pop    %rbp
</span></span><span class="line"><span class="cl">   0x000000000040139f &lt;+103&gt;: pop    %r12
</span></span><span class="line"><span class="cl">   0x00000000004013a1 &lt;+105&gt;: retq   
</span></span><span class="line"><span class="cl">End of assembler dump.
</span></span><span class="line"><span class="cl">       
</span></span></code></pre></div><ul>
<li>3-5：在函数调用时先保存相关寄存器值，<code>rbp</code>和<code>rbx</code>就是用来保存两个参数的寄存器</li>
<li>6：将寄存器<code>rdi</code>的值复制到寄存器<code>rbp</code></li>
<li>7：将寄存器<code>rsi</code>的值复制到寄存器<code>rbx</code></li>
</ul>
<p>其实看到这里就一直能够猜到答案是什么了。我们通过之前的<code>phase_1</code>函数能够大概知道需要输入一个值进行比较，如果比较正确就能解除炸弹。现在我们又进入到了这个比较函数，比较函数有两个参数，分别保存在两个寄存器里。我们正常的思维如果写一个比较函数，肯定一个参数是我们输入的值，一个参数是正确的值。</p>
<p>这里看到了<code>rsi</code>寄存器，我们还记得在<code>phase_1</code>函数中第 4 行的<code>esi</code>寄存器吗？这两个寄存器是同一个寄存器，只不过<code>esi</code>是寄存器的低 32 位，既然<code>esi</code>已经赋值了，那剩下的一个参数保存我们输入的内容。所以<code>esi</code>内存的内容就是我们需要的正确答案。我们只要把寄存器<code>esi</code>中的值打印出来，或者内存地址为<code>0x402400</code>的内容打印出来即可。可以通过以下三条命令查看。</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) p (char*)($esi)
</span></span><span class="line"><span class="cl">$5 = 0x402400 &#34;Border relations with Canada have never been better.&#34;
</span></span><span class="line"><span class="cl">(gdb) x/s 0x402400
</span></span><span class="line"><span class="cl">0x402400: &#34;Border relations with Canada have never been better.&#34;
</span></span><span class="line"><span class="cl">(gdb) x/s $esi
</span></span><span class="line"><span class="cl">0x402400: &#34;Border relations with Canada have never been better.&#34;
</span></span></code></pre></div><p>将答案复制，然后继续运行</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">The program being debugged has been started already.
</span></span><span class="line"><span class="cl">Start it from the beginning? (y or n) y
</span></span><span class="line"><span class="cl">Starting program: /home/dominic/learning-linux/bomb/bomb 
</span></span><span class="line"><span class="cl">Welcome to my fiendish little bomb. You have 6 phases with
</span></span><span class="line"><span class="cl">which to blow yourself up. Have a nice day!
</span></span><span class="line"><span class="cl">Border relations with Canada have never been better.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Breakpoint 2, 0x0000000000400ee0 in phase_1 ()
</span></span><span class="line"><span class="cl">(gdb) s
</span></span><span class="line"><span class="cl">Single stepping until exit from function phase_1,
</span></span><span class="line"><span class="cl">which has no line number information.
</span></span><span class="line"><span class="cl">main (argc=&lt;optimized out&gt;, argv=&lt;optimized out&gt;) at bomb.c:75
</span></span><span class="line"><span class="cl">75     phase_defused();                 /* Drat!  They figured it out!
</span></span><span class="line"><span class="cl">(gdb) s
</span></span><span class="line"><span class="cl">77     printf(&#34;Phase 1 defused. How about the next one?\n&#34;);
</span></span></code></pre></div><p>从 13 行<code>phase_defused()</code>可以知道我们已经解除了炸弹，从 15 行<code>printf</code>函数也可以看到，需要进行下一个炸弹的拆除。过来人的建议，在这里就开始分析<code>phase_2</code>，寻找答案，因为继续执行就要开始输入内容了，将无法调试。</p>
<h2 id="phase_2">phase_2</h2>
<p>继续分析第二个炸弹，</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas phase_2
</span></span><span class="line"><span class="cl">Dump of assembler code for function phase_2:
</span></span><span class="line"><span class="cl">   0x0000000000400efc &lt;+0&gt;: push   %rbp
</span></span><span class="line"><span class="cl">   0x0000000000400efd &lt;+1&gt;: push   %rbx
</span></span><span class="line"><span class="cl">   0x0000000000400efe &lt;+2&gt;: sub    $0x28,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400f02 &lt;+6&gt;: mov    %rsp,%rsi
</span></span><span class="line"><span class="cl">   0x0000000000400f05 &lt;+9&gt;: callq  0x40145c &lt;read_six_numbers&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f0a &lt;+14&gt;: cmpl   $0x1,(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000400f0e &lt;+18&gt;: je     0x400f30 &lt;phase_2+52&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f10 &lt;+20&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f15 &lt;+25&gt;: jmp    0x400f30 &lt;phase_2+52&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f17 &lt;+27&gt;: mov    -0x4(%rbx),%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f1a &lt;+30&gt;: add    %eax,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f1c &lt;+32&gt;: cmp    %eax,(%rbx)
</span></span><span class="line"><span class="cl">   0x0000000000400f1e &lt;+34&gt;: je     0x400f25 &lt;phase_2+41&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f20 &lt;+36&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f25 &lt;+41&gt;: add    $0x4,%rbx
</span></span><span class="line"><span class="cl">   0x0000000000400f29 &lt;+45&gt;: cmp    %rbp,%rbx
</span></span><span class="line"><span class="cl">   0x0000000000400f2c &lt;+48&gt;: jne    0x400f17 &lt;phase_2+27&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f2e &lt;+50&gt;: jmp    0x400f3c &lt;phase_2+64&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f30 &lt;+52&gt;: lea    0x4(%rsp),%rbx
</span></span><span class="line"><span class="cl">   0x0000000000400f35 &lt;+57&gt;: lea    0x18(%rsp),%rbp
</span></span><span class="line"><span class="cl">   0x0000000000400f3a &lt;+62&gt;: jmp    0x400f17 &lt;phase_2+27&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f3c &lt;+64&gt;: add    $0x28,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400f40 &lt;+68&gt;: pop    %rbx
</span></span><span class="line"><span class="cl">   0x0000000000400f41 &lt;+69&gt;: pop    %rbp
</span></span><span class="line"><span class="cl">   0x0000000000400f42 &lt;+70&gt;: retq   
</span></span><span class="line"><span class="cl">End of assembler dump.
</span></span></code></pre></div><ul>
<li>3-6：保存程序入口地址，变量等内容，就不再赘述了</li>
<li>7: 调用<code>read_six_numbers</code>函数，根据函数名我们可以猜测这个函数需要读入六个数字</li>
<li>8-9：比较寄存器<code>rsp</code>存的第一个数字是否等于<code>0x1</code>，如果等于就跳转到<code>phase_2+52</code>处继续执行，如果不等于就执行<code>explode_bomb</code>。栈中保存了六个输入的数字，保存顺序是从右往左，假如输入<code>1,2,3,4,5,6</code>。那么入栈的顺序就是<code>6,5,4,3,2,1</code>，寄存器<code>rsp</code>指向栈顶，也就是数字<code>1</code>的地址。</li>
<li>21:假设第一个数字正确，我们跳转到<code>&lt;+52&gt;</code>位置，也就是第 21 行，将<code>rsp+0x4</code>写入寄存器<code>rbx</code>，栈指针向上移动四个字节，也就是取第二个输入的参数，将它赋给寄存器<code>rbx</code></li>
<li>22：将<code>rsp+0x18</code>写入寄存器<code>rbp</code>，十六进制<code>0x18=24</code>，4 个字节一个数，刚好 6 个数，就是将输入参数的最后一个位置赋给寄存器<code>rbp</code></li>
<li>23：跳到<code>phase_2+27</code>继续执行</li>
<li>12：<code>rbx-0x4</code>赋给寄存器<code>eax</code>。第 21 行我们知道，<code>rbx</code>此时已经到第二个参数了，这一句就是说把第一个参数的值写入寄存器<code>eax</code></li>
<li>13：将<code>eax</code>翻一倍，第 8 行知道第一个参数值为<code>1</code>，所以此时<code>eax</code>值为<code>2</code></li>
<li>14-15：比较<code>eax</code>是否等于<code>rbx</code>。<code>rbx</code>此时保存的是第二个参数，这里也就是比较第二个参数是否等于<code>2</code>。如果等于跳转到<code>phase_2+41</code>位置，如果不等于就调用爆炸函数</li>
<li>17-18：假设第二个参数就是 2，我们跳过了炸弹来到第 17 行，将<code>rbx</code>继续上移，然后比较<code>rbp</code>是否等于<code>rbx</code>，我们知道<code>rbp</code>保存了最后一个参数的地址，所以这里的意思就是看看参数有没有到最后一个参数。</li>
<li>19：如果<code>rbx&lt;rbp</code>，意思就是还没到最后一个参数，就跳转到<code>phase_2+27</code></li>
<li>12：再次回到第 12 行，这里就是相当于一个循环了，让<code>rbx</code>一直向上移动，分别存入第 2，3，4，5，6 个参数，在移动到下一个参数时先保存当前参数到寄存器<code>eax</code>让其翻一倍，然后<code>rbx</code>再移动到下一个参数，比较<code>eax==rbx</code>。直到<code>rbx</code>越过了<code>rbp</code>。程序跳转到<code>phase_2+64</code>，将栈空间恢复。</li>
</ul>
<p>以上分析也可以得出答案了，我们只要输入一个以<code>1</code>为初值，公比为<code>2</code>，个数为<code>6</code>的等比数列就是答案，也就是<code>1 2 4 8 16 32</code>。</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> c
</span></span><span class="line"><span class="cl">Continuing.
</span></span><span class="line"><span class="cl">Phase <span class="m">1</span> defused. How about the next one?
</span></span><span class="line"><span class="cl"><span class="m">1</span> <span class="m">2</span> <span class="m">4</span> <span class="m">8</span> <span class="m">16</span> <span class="m">32</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Breakpoint 6, 0x00000000004015c4 in phase_defused <span class="o">()</span>
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> s
</span></span><span class="line"><span class="cl">Single stepping <span class="k">until</span> <span class="nb">exit</span> from <span class="k">function</span> phase_defused,
</span></span><span class="line"><span class="cl">which has no line number information.
</span></span><span class="line"><span class="cl">main <span class="o">(</span><span class="nv">argc</span><span class="o">=</span>&lt;optimized out&gt;, <span class="nv">argv</span><span class="o">=</span>&lt;optimized out&gt;<span class="o">)</span> at bomb.c:84
</span></span><span class="line"><span class="cl"><span class="m">84</span>     printf<span class="o">(</span><span class="s2">&#34;That&#39;s number 2.  Keep going!\n&#34;</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> s
</span></span></code></pre></div><p>这个炸弹的作者应该再心狠手辣一点，把函数名换成<code>read_some_numbers</code>，这样我们就不得不看这个函数的内容了，因为这个函数里还有一个坑，这个坑在函数名字上一句被填了。那就是这个函数会对参数个数做判断，如果小于 5 就爆炸。</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas read_six_numbers
</span></span><span class="line"><span class="cl">Dump of assembler code for function read_six_numbers:
</span></span><span class="line"><span class="cl">   0x000000000040145c &lt;+0&gt;: sub    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000401460 &lt;+4&gt;: mov    %rsi,%rdx
</span></span><span class="line"><span class="cl">   0x0000000000401463 &lt;+7&gt;: lea    0x4(%rsi),%rcx
</span></span><span class="line"><span class="cl">   0x0000000000401467 &lt;+11&gt;: lea    0x14(%rsi),%rax
</span></span><span class="line"><span class="cl">   0x000000000040146b &lt;+15&gt;: mov    %rax,0x8(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401470 &lt;+20&gt;: lea    0x10(%rsi),%rax
</span></span><span class="line"><span class="cl">   0x0000000000401474 &lt;+24&gt;: mov    %rax,(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401478 &lt;+28&gt;: lea    0xc(%rsi),%r9
</span></span><span class="line"><span class="cl">   0x000000000040147c &lt;+32&gt;: lea    0x8(%rsi),%r8
</span></span><span class="line"><span class="cl">   0x0000000000401480 &lt;+36&gt;: mov    $0x4025c3,%esi
</span></span><span class="line"><span class="cl">   0x0000000000401485 &lt;+41&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x000000000040148a &lt;+46&gt;: callq  0x400bf0 &lt;__isoc99_sscanf@plt&gt;
</span></span><span class="line"><span class="cl">   0x000000000040148f &lt;+51&gt;: cmp    $0x5,%eax
</span></span><span class="line"><span class="cl">   0x0000000000401492 &lt;+54&gt;: jg     0x401499 &lt;read_six_numbers+61&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401494 &lt;+56&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401499 &lt;+61&gt;: add    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x000000000040149d &lt;+65&gt;: retq   
</span></span><span class="line"><span class="cl">End of assembler dump.
</span></span></code></pre></div><ul>
<li>3：申请 24 个字节栈空间</li>
<li>4：<code>rdx=rsi</code>，将输入参数的第一个参数放到寄存器<code>rdx</code>中，为啥是第一个参数，因为<code>rsi</code>现在保存的地址是栈顶位置，栈顶目前保存就是第一个参数。</li>
<li>5：<code>rcx = rsi + 4</code>，把第二个参数的地址传给寄存器<code>rcx</code></li>
<li>6：<code>rax = rsi + 20</code>，把第六个参数的地址传给寄存器<code>rax</code></li>
<li>7：<code>rsp + 8 = rax</code>第八个参数</li>
<li>8：<code>rax = rsi + 16</code>，把第五个参数传给</li>
<li>9：<code>rsp = rax</code>第七个参数</li>
<li>10：<code>r9 = rsi + 12</code>把第四个参数传给寄存器<code>r9</code></li>
<li>11：<code>r8 = rsi + 8</code>把第三个参数传给寄存器<code>r8</code></li>
<li>12：</li>
<li>13：<code>eax = 0</code></li>
<li>14：调用输入函数<code>sscanf</code></li>
<li>15-17：函数返回值个数与 5 比较，如果小于 5 就爆炸，否则返回</li>
</ul>
<h2 id="phase_3">phase_3</h2>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">   0x0000000000400f43 &lt;+0&gt;: sub    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400f47 &lt;+4&gt;: lea    0xc(%rsp),%rcx
</span></span><span class="line"><span class="cl">   0x0000000000400f4c &lt;+9&gt;: lea    0x8(%rsp),%rdx
</span></span><span class="line"><span class="cl">   0x0000000000400f51 &lt;+14&gt;: mov    $0x4025cf,%esi
</span></span><span class="line"><span class="cl">   0x0000000000400f56 &lt;+19&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f5b &lt;+24&gt;: callq  0x400bf0 &lt;__isoc99_sscanf@plt&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f60 &lt;+29&gt;: cmp    $0x1,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f63 &lt;+32&gt;: jg     0x400f6a &lt;phase_3+39&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f65 &lt;+34&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f6a &lt;+39&gt;: cmpl   $0x7,0x8(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000400f6f &lt;+44&gt;: ja     0x400fad &lt;phase_3+106&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f71 &lt;+46&gt;: mov    0x8(%rsp),%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f75 &lt;+50&gt;: jmpq   *0x402470(,%rax,8)
</span></span><span class="line"><span class="cl">   0x0000000000400f7c &lt;+57&gt;: mov    $0xcf,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f81 &lt;+62&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f83 &lt;+64&gt;: mov    $0x2c3,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f88 &lt;+69&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f8a &lt;+71&gt;: mov    $0x100,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f8f &lt;+76&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f91 &lt;+78&gt;: mov    $0x185,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f96 &lt;+83&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f98 &lt;+85&gt;: mov    $0xce,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f9d &lt;+90&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f9f &lt;+92&gt;: mov    $0x2aa,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fa4 &lt;+97&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fa6 &lt;+99&gt;: mov    $0x147,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fab &lt;+104&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fad &lt;+106&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fb2 &lt;+111&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fb7 &lt;+116&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fb9 &lt;+118&gt;: mov    $0x137,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fbe &lt;+123&gt;: cmp    0xc(%rsp),%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fc2 &lt;+127&gt;: je     0x400fc9 &lt;phase_3+134&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fc4 &lt;+129&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fc9 &lt;+134&gt;: add    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400fcd &lt;+138&gt;: retq   
</span></span></code></pre></div><ul>
<li>1：开辟 24 字节的栈空间</li>
<li>2：<code>rcx = rsp + 12</code>第二个参数</li>
<li>3：<code>rdx = rsp + 8</code>第一个参数</li>
<li>4-8：和<code>phase_2</code>里<code>read_six_numbers</code>函数中的第 13 行开始一样，输入数据，判断一下输入参数的个数，只不过这里是返回值个数大于 1，如果参数个数正确就跳到<code>phase_3+39</code>也就是第 10 行，否则引爆炸弹。</li>
<li>10-11：如果<code>7 &lt; rsp + 8 等价于 7 &lt; rdx 等价于 7 &lt; 第一个参数</code>就跳转到<code>phase_3+106</code>，爆炸。这里确定第一个数必须小于 7</li>
<li>12：<code>eax = rsp + 8 等价于 eax = 第一个参数</code></li>
<li>13：跳转至<code>0x402470 + 8 * rax</code>处，具体跳转到哪里根据第一个值做判断</li>
<li>14：<code>eax = 207</code></li>
<li>15：跳转至<code>phase_3+123</code>,即 32 行</li>
<li>16：<code>eax = 707</code></li>
<li>17：跳转到 32 行</li>
<li>18：<code>eax = 256</code></li>
<li>19：跳转到 32 行</li>
<li>20：<code>eax = 389</code></li>
<li>21-27：以此类推</li>
<li>29：<code>eax = 0</code></li>
<li>30：</li>
<li>31：<code>eax = 311</code></li>
<li>32-34：比较<code>eax</code>和<code>rsp + 12</code> 等价于 比较 第二个参数和<code>eax</code>。如果相等就返回，如果不等就引爆。</li>
</ul>
<p>分析至此，我们也就知道了程序的大概流程，输入两个值，第一个值必须小于等于 7，第二个值根据第一个值来确定，具体等于多少，根据跳转表确定，因为第一个值有八个数，也就对应着汇编中八段寄存器<code>eax</code>赋值的过程，我们只要输入第一个合法的数值，然后再打印出寄存器<code>eax</code>的值，即可确定答案。</p>
<p>比如我们先测试一下第一个值为 0 时，对应的第二个值为多少，我们输入<code>0  10</code>，因为只是测试，第二个值任意。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">That&#39;s number 2.  Keep going! //接上个炸弹后面
</span></span><span class="line"><span class="cl">88     input = read_line();
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">0 10              //输入测试答案
</span></span><span class="line"><span class="cl">89     phase_3(input);
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">Breakpoint 4, 0x0000000000400f43 in phase_3 ()
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">Single stepping until exit from function phase_3,
</span></span><span class="line"><span class="cl">which has no line number information.
</span></span><span class="line"><span class="cl">Breakpoint 2, 0x000000000040143a in explode_bomb ()
</span></span><span class="line"><span class="cl">(gdb) p $eax
</span></span><span class="line"><span class="cl">$14 = 207         //207即是答案
</span></span></code></pre></div><p>输入真正答案测试，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">0 207                         //输入答案
</span></span><span class="line"><span class="cl">89     phase_3(input);
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">Breakpoint 4, 0x0000000000400f43 in phase_3 ()
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">Single stepping until exit from function phase_3,
</span></span><span class="line"><span class="cl">which has no line number information.
</span></span><span class="line"><span class="cl">main (argc=&lt;optimized out&gt;, argv=&lt;optimized out&gt;) at bomb.c:90
</span></span><span class="line"><span class="cl">90     phase_defused();    //炸弹拆除
</span></span><span class="line"><span class="cl">(gdb) 
</span></span><span class="line"><span class="cl">91     printf(&#34;Halfway there!\n&#34;);
</span></span></code></pre></div><p>我们上面说过，第一个值有八种可能，所以这题答案也有八个，我们只要挨个测试<code>0-7</code>，分别打印出寄存器<code>eax</code>的值就可以得到所有答案。他们分别是</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">0 207
</span></span><span class="line"><span class="cl">1 311
</span></span><span class="line"><span class="cl">2 707
</span></span><span class="line"><span class="cl">3 256
</span></span><span class="line"><span class="cl">4 389
</span></span><span class="line"><span class="cl">5 206
</span></span><span class="line"><span class="cl">6 682
</span></span><span class="line"><span class="cl">7 327
</span></span></code></pre></div><h2 id="phase_4">phase_4</h2>
<p>行百里者半九十，NO</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas phase_4
</span></span><span class="line"><span class="cl">Dump of assembler code for function phase_4:
</span></span><span class="line"><span class="cl">   0x000000000040100c &lt;+0&gt;: sub    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000401010 &lt;+4&gt;: lea    0xc(%rsp),%rcx
</span></span><span class="line"><span class="cl">   0x0000000000401015 &lt;+9&gt;: lea    0x8(%rsp),%rdx
</span></span><span class="line"><span class="cl">   0x000000000040101a &lt;+14&gt;: mov    $0x4025cf,%esi
</span></span><span class="line"><span class="cl">   0x000000000040101f &lt;+19&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x0000000000401024 &lt;+24&gt;: callq  0x400bf0 &lt;__isoc99_sscanf@plt&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401029 &lt;+29&gt;: cmp    $0x2,%eax
</span></span><span class="line"><span class="cl">   0x000000000040102c &lt;+32&gt;: jne    0x401035 &lt;phase_4+41&gt;
</span></span><span class="line"><span class="cl">   0x000000000040102e &lt;+34&gt;: cmpl   $0xe,0x8(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401033 &lt;+39&gt;: jbe    0x40103a &lt;phase_4+46&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401035 &lt;+41&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x000000000040103a &lt;+46&gt;: mov    $0xe,%edx
</span></span><span class="line"><span class="cl">   0x000000000040103f &lt;+51&gt;: mov    $0x0,%esi
</span></span><span class="line"><span class="cl">   0x0000000000401044 &lt;+56&gt;: mov    0x8(%rsp),%edi
</span></span><span class="line"><span class="cl">   0x0000000000401048 &lt;+60&gt;: callq  0x400fce &lt;func4&gt;
</span></span><span class="line"><span class="cl">   0x000000000040104d &lt;+65&gt;: test   %eax,%eax
</span></span><span class="line"><span class="cl">   0x000000000040104f &lt;+67&gt;: jne    0x401058 &lt;phase_4+76&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401051 &lt;+69&gt;: cmpl   $0x0,0xc(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401056 &lt;+74&gt;: je     0x40105d &lt;phase_4+81&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401058 &lt;+76&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x000000000040105d &lt;+81&gt;: add    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000401061 &lt;+85&gt;: retq   
</span></span></code></pre></div><ul>
<li>1-8：开辟空间，保存参数信息，调用输入函数，和上面的分析重复，不再赘述。注意的是第 6 行，<code>x/s 0x4025cf</code>可知两个参数是整型数值。</li>
<li>9-10：参数个数必须等于 2，否则引爆</li>
<li>11-12：<code>14</code>与<code>rsp + 8</code>比较，等价于<code>14</code>与第一个参数比较。表示第一个参数必须小于等于 14，否则引爆。</li>
<li>14：<code>edx = 14</code></li>
<li>15：<code>esi = 0</code></li>
<li>16：<code>edi = rsp + 8</code>即<code>edi = 第一个参数</code></li>
<li>17：调用函数<code>fun4</code>，参数分别为<code>edi 0 14</code></li>
<li>18：测试返回值是否为 0，如果不为 0，引爆</li>
<li>20-22：比较<code>0</code>和<code>rsp + 12</code>，如果不等，引爆，否则返回</li>
</ul>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas func4
</span></span><span class="line"><span class="cl">Dump of assembler code for function func4:
</span></span><span class="line"><span class="cl">   0x0000000000400fce &lt;+0&gt;: sub    $0x8,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400fd2 &lt;+4&gt;: mov    %edx,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fd4 &lt;+6&gt;: sub    %esi,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fd6 &lt;+8&gt;: mov    %eax,%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400fd8 &lt;+10&gt;: shr    $0x1f,%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400fdb &lt;+13&gt;: add    %ecx,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fdd &lt;+15&gt;: sar    %eax
</span></span><span class="line"><span class="cl">   0x0000000000400fdf &lt;+17&gt;: lea    (%rax,%rsi,1),%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400fe2 &lt;+20&gt;: cmp    %edi,%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400fe4 &lt;+22&gt;: jle    0x400ff2 &lt;func4+36&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fe6 &lt;+24&gt;: lea    -0x1(%rcx),%edx
</span></span><span class="line"><span class="cl">   0x0000000000400fe9 &lt;+27&gt;: callq  0x400fce &lt;func4&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fee &lt;+32&gt;: add    %eax,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400ff0 &lt;+34&gt;: jmp    0x401007 &lt;func4+57&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400ff2 &lt;+36&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400ff7 &lt;+41&gt;: cmp    %edi,%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400ff9 &lt;+43&gt;: jge    0x401007 &lt;func4+57&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400ffb &lt;+45&gt;: lea    0x1(%rcx),%esi
</span></span><span class="line"><span class="cl">   0x0000000000400ffe &lt;+48&gt;: callq  0x400fce &lt;func4&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401003 &lt;+53&gt;: lea    0x1(%rax,%rax,1),%eax
</span></span><span class="line"><span class="cl">   0x0000000000401007 &lt;+57&gt;: add    $0x8,%rsp
</span></span><span class="line"><span class="cl">   0x000000000040100b &lt;+61&gt;: retq   
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="nf">func</span> <span class="p">(</span><span class="n">edi</span><span class="p">,</span> <span class="n">esi</span><span class="p">,</span> <span class="n">edx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="c1">// edi = 第一个参数, esi = 0, edx = 14
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">edx</span>            <span class="c1">// 4:mov %edx, %eax
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">eax</span> <span class="o">-</span><span class="n">esi</span>       <span class="c1">// 5:sub esi, %eax
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">edx</span> <span class="o">-</span><span class="n">esi</span>
</span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="n">eax</span>            <span class="c1">// 6:mov %eax, %ecx
</span></span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span>
</span></span><span class="line"><span class="cl">   <span class="n">eсx</span> <span class="o">=</span> <span class="n">ecx</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span>      <span class="c1">// 7:shr  $0x1f, %ecx
</span></span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="p">(</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span>
</span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">eax</span> <span class="o">+</span> <span class="n">ecx</span>      <span class="c1">// 8:add %ecx, %eax
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="p">(</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">+</span> <span class="p">((</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">)</span><span class="c1">//替换eax和ecx
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">eax</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">;</span>       <span class="c1">// 9:sar %eax
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="p">((</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">+</span><span class="p">((</span><span class="n">edx</span> <span class="o">-</span><span class="n">esi</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">))</span> <span class="o">/</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="n">eax</span> <span class="o">+</span> <span class="n">esi</span> <span class="o">*</span> <span class="mi">1</span>   <span class="c1">// 10:lea (rax,ersi,1), %ecx
</span></span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="p">((</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">+</span><span class="p">((</span><span class="n">edx</span> <span class="o">-</span><span class="n">esi</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">))</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">esi</span> <span class="o">*</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="p">((</span><span class="mi">14</span> <span class="o">-</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="p">((</span><span class="mi">14</span> <span class="o">-</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">))</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="mi">7</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="c1">// 11:cmp %edi, %ecx
</span></span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">ecx</span> <span class="o">&lt;=</span> <span class="n">edi</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// 12:jle 400ff2
</span></span></span><span class="line"><span class="cl">      <span class="n">eax</span> <span class="o">=</span> <span class="mi">0</span>    <span class="c1">// mov $0x0,%eax
</span></span></span><span class="line"><span class="cl">      <span class="c1">// 18:cmp %edi, %ecx
</span></span></span><span class="line"><span class="cl">      <span class="k">if</span><span class="p">(</span><span class="n">ecx</span> <span class="o">&gt;=</span> <span class="n">edi</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="c1">// 19:jge    0x401007 &lt;func4+57&gt;
</span></span></span><span class="line"><span class="cl">         <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="c1">//由此可以得知道 edx == edi
</span></span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="phase_5">phase_5</h2>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">   0x0000000000401062 &lt;+0&gt;: push   %rbx
</span></span><span class="line"><span class="cl">   0x0000000000401063 &lt;+1&gt;: sub    $0x20,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000401067 &lt;+5&gt;: mov    %rdi,%rbx
</span></span><span class="line"><span class="cl">   0x000000000040106a &lt;+8&gt;: mov    %fs:0x28,%rax
</span></span><span class="line"><span class="cl">   0x0000000000401073 &lt;+17&gt;: mov    %rax,0x18(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401078 &lt;+22&gt;: xor    %eax,%eax
</span></span><span class="line"><span class="cl">   0x000000000040107a &lt;+24&gt;: callq  0x40131b &lt;string_length&gt;
</span></span><span class="line"><span class="cl">   0x000000000040107f &lt;+29&gt;: cmp    $0x6,%eax
</span></span><span class="line"><span class="cl">   0x0000000000401082 &lt;+32&gt;: je     0x4010d2 &lt;phase_5+112&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401084 &lt;+34&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401089 &lt;+39&gt;: jmp    0x4010d2 &lt;phase_5+112&gt;
</span></span><span class="line"><span class="cl">   0x000000000040108b &lt;+41&gt;: movzbl (%rbx,%rax,1),%ecx
</span></span><span class="line"><span class="cl">   0x000000000040108f &lt;+45&gt;: mov    %cl,(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401092 &lt;+48&gt;: mov    (%rsp),%rdx
</span></span><span class="line"><span class="cl">   0x0000000000401096 &lt;+52&gt;: and    $0xf,%edx
</span></span><span class="line"><span class="cl">   0x0000000000401099 &lt;+55&gt;: movzbl 0x4024b0(%rdx),%edx
</span></span><span class="line"><span class="cl">   0x00000000004010a0 &lt;+62&gt;: mov    %dl,0x10(%rsp,%rax,1)
</span></span><span class="line"><span class="cl">   0x00000000004010a4 &lt;+66&gt;: add    $0x1,%rax
</span></span><span class="line"><span class="cl">   0x00000000004010a8 &lt;+70&gt;: cmp    $0x6,%rax
</span></span><span class="line"><span class="cl">   0x00000000004010ac &lt;+74&gt;: jne    0x40108b &lt;phase_5+41&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010ae &lt;+76&gt;: movb   $0x0,0x16(%rsp)
</span></span><span class="line"><span class="cl">   0x00000000004010b3 &lt;+81&gt;: mov    $0x40245e,%esi
</span></span><span class="line"><span class="cl">      0x00000000004010b8 &lt;+86&gt;: lea    0x10(%rsp),%rdi
</span></span><span class="line"><span class="cl">   0x00000000004010bd &lt;+91&gt;: callq  0x401338 &lt;strings_not_equal&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010c2 &lt;+96&gt;: test   %eax,%eax
</span></span><span class="line"><span class="cl">   0x00000000004010c4 &lt;+98&gt;: je     0x4010d9 &lt;phase_5+119&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010c6 &lt;+100&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010cb &lt;+105&gt;: nopl   0x0(%rax,%rax,1)
</span></span><span class="line"><span class="cl">   0x00000000004010d0 &lt;+110&gt;: jmp    0x4010d9 &lt;phase_5+119&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010d2 &lt;+112&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x00000000004010d7 &lt;+117&gt;: jmp    0x40108b &lt;phase_5+41&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010d9 &lt;+119&gt;: mov    0x18(%rsp),%rax
</span></span><span class="line"><span class="cl">   0x00000000004010de &lt;+124&gt;: xor    %fs:0x28,%rax
</span></span><span class="line"><span class="cl">   0x00000000004010e7 &lt;+133&gt;: je     0x4010ee &lt;phase_5+140&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010e9 &lt;+135&gt;: callq  0x400b30 &lt;__stack_chk_fail@plt&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010ee &lt;+140&gt;: add    $0x20,%rsp
</span></span><span class="line"><span class="cl">   0x00000000004010f2 &lt;+144&gt;: pop    %rbx
</span></span><span class="line"><span class="cl">   0x00000000004010f3 &lt;+145&gt;: retq   
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>GDB 调试入门</title>
      <link>https://lifeislife.cn/posts/gdb%E8%B0%83%E8%AF%95%E5%85%A5%E9%97%A8/</link>
      <pubDate>Sun, 29 Aug 2021 18:40:16 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/gdb%E8%B0%83%E8%AF%95%E5%85%A5%E9%97%A8/</guid>
      <description>&lt;h2 id=&#34;file-加载程序&#34;&gt;file 加载程序&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; file bomb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading symbols from bomb...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;set-args-带参数调试&#34;&gt;set args 带参数调试&lt;/h2&gt;
&lt;p&gt;有时候程序不是直接可以运行的，需要加上一些必要的参数。带上参数运行很容易，只要在程序名后加上相应参数即可，但是如何带上参数进行调试呢？这就需要&lt;code&gt;set args&lt;/code&gt;命令。&lt;/p&gt;
&lt;p&gt;比如在&lt;code&gt;BombLab&lt;/code&gt;实验中，我们不可能一次解决所有&lt;code&gt;phase&lt;/code&gt;，但是每次重新调试，已经解决的&lt;code&gt;phase&lt;/code&gt;还要重新输入一次答案，这就很麻烦，好在这个实验的作者也考虑到了，他支持读取文本。我们可以把答案预先写入一个文本文件中，程序读取已经保存的答案即可跳过相应的&lt;code&gt;phase&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;假设我们把答案写入了&lt;code&gt;solutions.txt&lt;/code&gt;文件中，首先，我们加载程序，然后通过&lt;code&gt;set args solutions.txt&lt;/code&gt;设置运行参数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; file bomb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading symbols from bomb...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; args solutions.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Starting program: /home/dominic/learning-linux/bomb/bomb solutions.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Welcome to my fiendish little bomb. You have &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; phases with
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which to blow yourself up. Have a nice day!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Phase &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; defused. How about the next one?
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;That&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;s number 2.  Keep going!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;list-查看源码&#34;&gt;list 查看源码&lt;/h2&gt;
&lt;h3 id=&#34;查看-10-行源码&#34;&gt;查看 10 行源码&lt;/h3&gt;
&lt;p&gt;每条命令显示 10 行代码&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#include &amp;#34;support.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;26&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#include &amp;#34;phases.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;27&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; /* 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;29&lt;/span&gt;  * Note to self: Remember to erase this file so my victims will have no
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;30&lt;/span&gt;  * idea what is going on, and so they will all blow up in a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;31&lt;/span&gt;  * spectaculary fiendish explosion. -- Dr. Evil 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;  */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;33&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;34&lt;/span&gt; FILE *infile&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;35&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;36&lt;/span&gt; int main&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;int argc, char *argv&lt;span class=&#34;o&#34;&gt;[])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;37&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;38&lt;/span&gt;     char *input&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;39&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;40&lt;/span&gt;     /* Note to self: remember to port this bomb to Windows and put a 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;41&lt;/span&gt;      * fantastic GUI on it. */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;set-list-num-设置默认显示代码行数&#34;&gt;set list num 设置默认显示代码行数&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) set list 20   //默认显示20行代码
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;list-linenumber-查看指定行代码&#34;&gt;list linenumber 查看指定行代码&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) l 10  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) l main.h : 10 //指定main.c文件中的第十行
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;list-function-查看指定函数的代码&#34;&gt;list function 查看指定函数的代码&lt;/h3&gt;
&lt;h2 id=&#34;break-打断点&#34;&gt;break 打断点&lt;/h2&gt;
&lt;h3 id=&#34;break-linenum-对指定行打断点&#34;&gt;break linenum 对指定行打断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; b &lt;span class=&#34;m&#34;&gt;36&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Note: breakpoint &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; also &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; at pc 0x400da0.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; at 0x400da0: file bomb.c, line 37.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;break-function-对指定函数打断点&#34;&gt;break function 对指定函数打断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; b main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; at 0x400da0: file bomb.c, line 37.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; b phase_1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; at 0x400ee0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;删除断点包括禁用断点&#34;&gt;删除断点包括禁用断点&lt;/h2&gt;
&lt;h3 id=&#34;delete-删除所有断点&#34;&gt;delete 删除所有断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; delete 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Delete all breakpoints? &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;y or n&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;disable-breakpoint-禁用断点&#34;&gt;disable breakpoint 禁用断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; info b &lt;span class=&#34;c1&#34;&gt;#先看有哪些断点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Num     Type           Disp Enb Address            What
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;       breakpoint     keep y   0x0000000000400da0 in main at bomb.c:37
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;       breakpoint     keep y   0x0000000000400ee0 &amp;lt;phase_1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; d &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#禁用第三号断点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; info b &lt;span class=&#34;c1&#34;&gt;#再次查看断点信息发现已经没有第三号断点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Num     Type           Disp Enb Address            What
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;       breakpoint     keep y   0x0000000000400ee0 &amp;lt;phase_1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;clear-function-删除一个函数中所有的断点&#34;&gt;clear function 删除一个函数中所有的断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; info b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Num     Type           Disp Enb Address            What
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;       breakpoint     keep y   0x0000000000400ee0 &amp;lt;phase_1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; clear phase_1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; info b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Deleted breakpoint &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; No breakpoints or watchpoints.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;启动与退出&#34;&gt;启动与退出&lt;/h2&gt;
&lt;h3 id=&#34;run-启动程序直到遇到断点&#34;&gt;run 启动程序直到遇到断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) run  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;start-启动程序并在第一条代码处停下&#34;&gt;start 启动程序并在第一条代码处停下&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;x-配置-gdb-常用命令&#34;&gt;x 配置 gdb 常用命令&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gdb -q -x gdbinit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;//gdbinit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;display/z $xs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;display/z $x6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;display/z $x7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;set disassemble-next-line on
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;b _start
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;target remote: 34
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;有了配置文件，就不用每次启动 gdb 时都要重新输入一遍调试命令。&lt;/p&gt;
&lt;h3 id=&#34;quit-退出调试&#34;&gt;quit 退出调试&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) quit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;调试命令&#34;&gt;调试命令&lt;/h2&gt;
&lt;h3 id=&#34;print-打印变量值&#34;&gt;print 打印变量值&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;格式化字符 (/fmt)&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;/x&lt;/td&gt;
					&lt;td&gt;以十六进制的形式打印出整数。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;/d&lt;/td&gt;
					&lt;td&gt;以有符号、十进制的形式打印出整数。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;/u&lt;/td&gt;
					&lt;td&gt;以无符号、十进制的形式打印出整数。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;/o&lt;/td&gt;
					&lt;td&gt;以八进制的形式打印出整数。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;/t&lt;/td&gt;
					&lt;td&gt;以二进制的形式打印出整数。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;/f&lt;/td&gt;
					&lt;td&gt;以浮点数的形式打印变量或表达式的值。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;/c&lt;/td&gt;
					&lt;td&gt;以字符形式打印变量或表达式的值。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p i       # 10进制
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$5 = 3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p/x i     # 16进制
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$6 = 0x3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p/o i     # 8进制
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$7 = 03
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;打印地址值&#34;&gt;打印地址值&lt;/h3&gt;
&lt;p&gt;表示从内存地址 0x54320 读取内容，h 表示以双字节为单位，3 表示输出 3 个单位，u 表示按照十六进制显示。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) x/3uh 0x54320 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看当前程序栈的内容：x/10x $sp–&amp;gt;打印 stack 的前 10 个元素
查看当前程序栈的信息：info frame&amp;mdash;-list general info about the frame
查看当前程序栈的参数：info args—lists arguments to the function
查看当前程序栈的局部变量：info locals—list variables stored in the frame
查看当前寄存器的值：info registers(不包括浮点寄存器)&lt;/p&gt;
&lt;h3 id=&#34;ptype-打印变量类型&#34;&gt;ptype 打印变量类型&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) ptype i
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type = int
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) ptype array[i]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type = int
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) ptype array
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type = int [12]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;display-跟踪显示变量&#34;&gt;display 跟踪显示变量&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;print&lt;/code&gt;命令可以打印出变量的值，但是只是一次性的。如果我们想要跟踪某个变量的变化，可以使用&lt;code&gt;display&lt;/code&gt;命令，每当程序在断点处停下，都会打印出跟踪的变量值。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) display 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;info display&lt;/code&gt;查看已跟踪的变量，&lt;code&gt;delete display&lt;/code&gt;取消跟踪显示变量。&lt;/p&gt;
&lt;h3 id=&#34;step-执行一行代码&#34;&gt;step 执行一行代码&lt;/h3&gt;
&lt;p&gt;执行一行代码，如果改行代码是函数，将进入函数内部。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;finish-跳出函数&#34;&gt;finish 跳出函数&lt;/h3&gt;
&lt;p&gt;如果通过&lt;code&gt;s&lt;/code&gt;单步调试进入到函数内部，想要跳出这个函数体，可以执行 &lt;code&gt;finish&lt;/code&gt;命令。如果想要跳出函数体必须要&lt;strong&gt;保证函数体内不能有有效断点&lt;/strong&gt;，否则无法跳出。&lt;/p&gt;
&lt;h3 id=&#34;next-执行一行代码&#34;&gt;next 执行一行代码&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;next&lt;/code&gt; 命令和 &lt;code&gt;step&lt;/code&gt; 命令功能是相似的，只是在使用 &lt;code&gt;next&lt;/code&gt; 调试程序的时候不会进入到函数体内部，&lt;code&gt;next&lt;/code&gt; 可以缩写为 &lt;code&gt;n&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;until-跳出循环体&#34;&gt;until 跳出循环体&lt;/h3&gt;
&lt;p&gt;通过 until 命令可以直接跳出某个循环体，这样就能提高调试效率了。如果想直接从循环体中跳出，必须要保证，&lt;strong&gt;要跳出的循环体内部不能有有效的断点&lt;/strong&gt;，&lt;strong&gt;必须要在循环体的开始 / 结束行执行该命令&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;layout-分割窗口边调试边看源码&#34;&gt;layout 分割窗口，边调试边看源码&lt;/h2&gt;
&lt;h3 id=&#34;layout-src&#34;&gt;layout src&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153452.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153452.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;layout-asm&#34;&gt;layout asm&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153520.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153520.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;layout-split&#34;&gt;layout split&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153555.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153555.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;远程调试&#34;&gt;远程调试&lt;/h2&gt;
&lt;h3 id=&#34;-s--s&#34;&gt;&lt;code&gt;-s -S&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;-s&lt;/code&gt;启动&lt;code&gt;gdb server&lt;/code&gt;，默认端口号为 1234
&lt;code&gt;-S&lt;/code&gt;让程序在&lt;code&gt;_start&lt;/code&gt;处停下。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="file-加载程序">file 加载程序</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> file bomb
</span></span><span class="line"><span class="cl">Reading symbols from bomb...
</span></span></code></pre></div><h2 id="set-args-带参数调试">set args 带参数调试</h2>
<p>有时候程序不是直接可以运行的，需要加上一些必要的参数。带上参数运行很容易，只要在程序名后加上相应参数即可，但是如何带上参数进行调试呢？这就需要<code>set args</code>命令。</p>
<p>比如在<code>BombLab</code>实验中，我们不可能一次解决所有<code>phase</code>，但是每次重新调试，已经解决的<code>phase</code>还要重新输入一次答案，这就很麻烦，好在这个实验的作者也考虑到了，他支持读取文本。我们可以把答案预先写入一个文本文件中，程序读取已经保存的答案即可跳过相应的<code>phase</code>。</p>
<p>假设我们把答案写入了<code>solutions.txt</code>文件中，首先，我们加载程序，然后通过<code>set args solutions.txt</code>设置运行参数。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> file bomb
</span></span><span class="line"><span class="cl">Reading symbols from bomb...
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> <span class="nb">set</span> args solutions.txt 
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> r
</span></span><span class="line"><span class="cl">Starting program: /home/dominic/learning-linux/bomb/bomb solutions.txt 
</span></span><span class="line"><span class="cl">Welcome to my fiendish little bomb. You have <span class="m">6</span> phases with
</span></span><span class="line"><span class="cl">which to blow yourself up. Have a nice day!
</span></span><span class="line"><span class="cl">Phase <span class="m">1</span> defused. How about the next one?
</span></span><span class="line"><span class="cl">That<span class="err">&#39;</span>s number 2.  Keep going!
</span></span></code></pre></div><h2 id="list-查看源码">list 查看源码</h2>
<h3 id="查看-10-行源码">查看 10 行源码</h3>
<p>每条命令显示 10 行代码</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> l
</span></span><span class="line"><span class="cl"><span class="m">23</span> <span class="c1">#include &lt;stdio.h&gt;</span>
</span></span><span class="line"><span class="cl"><span class="m">24</span> <span class="c1">#include &lt;stdlib.h&gt;</span>
</span></span><span class="line"><span class="cl"><span class="m">25</span> <span class="c1">#include &#34;support.h&#34;</span>
</span></span><span class="line"><span class="cl"><span class="m">26</span> <span class="c1">#include &#34;phases.h&#34;</span>
</span></span><span class="line"><span class="cl"><span class="m">27</span> 
</span></span><span class="line"><span class="cl"><span class="m">28</span> /* 
</span></span><span class="line"><span class="cl"><span class="m">29</span>  * Note to self: Remember to erase this file so my victims will have no
</span></span><span class="line"><span class="cl"><span class="m">30</span>  * idea what is going on, and so they will all blow up in a
</span></span><span class="line"><span class="cl"><span class="m">31</span>  * spectaculary fiendish explosion. -- Dr. Evil 
</span></span><span class="line"><span class="cl"><span class="m">32</span>  */
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> l
</span></span><span class="line"><span class="cl"><span class="m">33</span> 
</span></span><span class="line"><span class="cl"><span class="m">34</span> FILE *infile<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="m">35</span> 
</span></span><span class="line"><span class="cl"><span class="m">36</span> int main<span class="o">(</span>int argc, char *argv<span class="o">[])</span>
</span></span><span class="line"><span class="cl"><span class="m">37</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl"><span class="m">38</span>     char *input<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="m">39</span> 
</span></span><span class="line"><span class="cl"><span class="m">40</span>     /* Note to self: remember to port this bomb to Windows and put a 
</span></span><span class="line"><span class="cl"><span class="m">41</span>      * fantastic GUI on it. */
</span></span><span class="line"><span class="cl"><span class="m">42</span>
</span></span></code></pre></div><h3 id="set-list-num-设置默认显示代码行数">set list num 设置默认显示代码行数</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) set list 20   //默认显示20行代码
</span></span></code></pre></div><h3 id="list-linenumber-查看指定行代码">list linenumber 查看指定行代码</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) l 10  
</span></span><span class="line"><span class="cl">(gdb) l main.h : 10 //指定main.c文件中的第十行
</span></span></code></pre></div><h3 id="list-function-查看指定函数的代码">list function 查看指定函数的代码</h3>
<h2 id="break-打断点">break 打断点</h2>
<h3 id="break-linenum-对指定行打断点">break linenum 对指定行打断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> b <span class="m">36</span>
</span></span><span class="line"><span class="cl">Note: breakpoint <span class="m">1</span> also <span class="nb">set</span> at pc 0x400da0.
</span></span><span class="line"><span class="cl">Breakpoint <span class="m">2</span> at 0x400da0: file bomb.c, line 37.
</span></span></code></pre></div><h3 id="break-function-对指定函数打断点">break function 对指定函数打断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> b main
</span></span><span class="line"><span class="cl">Breakpoint <span class="m">3</span> at 0x400da0: file bomb.c, line 37.
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> b phase_1
</span></span><span class="line"><span class="cl">Breakpoint <span class="m">4</span> at 0x400ee0
</span></span></code></pre></div><h2 id="删除断点包括禁用断点">删除断点包括禁用断点</h2>
<h3 id="delete-删除所有断点">delete 删除所有断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> delete 
</span></span><span class="line"><span class="cl">Delete all breakpoints? <span class="o">(</span>y or n<span class="o">)</span> y
</span></span></code></pre></div><h3 id="disable-breakpoint-禁用断点">disable breakpoint 禁用断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> info b <span class="c1">#先看有哪些断点</span>
</span></span><span class="line"><span class="cl">Num     Type           Disp Enb Address            What
</span></span><span class="line"><span class="cl"><span class="m">3</span>       breakpoint     keep y   0x0000000000400da0 in main at bomb.c:37
</span></span><span class="line"><span class="cl"><span class="m">4</span>       breakpoint     keep y   0x0000000000400ee0 &lt;phase_1&gt;
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> d <span class="m">3</span> <span class="c1">#禁用第三号断点</span>
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> info b <span class="c1">#再次查看断点信息发现已经没有第三号断点</span>
</span></span><span class="line"><span class="cl">Num     Type           Disp Enb Address            What
</span></span><span class="line"><span class="cl"><span class="m">4</span>       breakpoint     keep y   0x0000000000400ee0 &lt;phase_1&gt;
</span></span></code></pre></div><h3 id="clear-function-删除一个函数中所有的断点">clear function 删除一个函数中所有的断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> info b
</span></span><span class="line"><span class="cl">Num     Type           Disp Enb Address            What
</span></span><span class="line"><span class="cl"><span class="m">4</span>       breakpoint     keep y   0x0000000000400ee0 &lt;phase_1&gt;
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> clear phase_1
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> info b
</span></span><span class="line"><span class="cl">Deleted breakpoint <span class="m">4</span> No breakpoints or watchpoints.
</span></span></code></pre></div><h2 id="启动与退出">启动与退出</h2>
<h3 id="run-启动程序直到遇到断点">run 启动程序直到遇到断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) run  
</span></span></code></pre></div><h3 id="start-启动程序并在第一条代码处停下">start 启动程序并在第一条代码处停下</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) start
</span></span></code></pre></div><h3 id="x-配置-gdb-常用命令">x 配置 gdb 常用命令</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">gdb -q -x gdbinit
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">//gdbinit
</span></span><span class="line"><span class="cl">display/z $xs
</span></span><span class="line"><span class="cl">display/z $x6
</span></span><span class="line"><span class="cl">display/z $x7
</span></span><span class="line"><span class="cl">set disassemble-next-line on
</span></span><span class="line"><span class="cl">b _start
</span></span><span class="line"><span class="cl">target remote: 34
</span></span></code></pre></div><p>有了配置文件，就不用每次启动 gdb 时都要重新输入一遍调试命令。</p>
<h3 id="quit-退出调试">quit 退出调试</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) quit
</span></span></code></pre></div><h2 id="调试命令">调试命令</h2>
<h3 id="print-打印变量值">print 打印变量值</h3>
<table>
	<thead>
			<tr>
					<th>格式化字符 (/fmt)</th>
					<th>说明</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>/x</td>
					<td>以十六进制的形式打印出整数。</td>
			</tr>
			<tr>
					<td>/d</td>
					<td>以有符号、十进制的形式打印出整数。</td>
			</tr>
			<tr>
					<td>/u</td>
					<td>以无符号、十进制的形式打印出整数。</td>
			</tr>
			<tr>
					<td>/o</td>
					<td>以八进制的形式打印出整数。</td>
			</tr>
			<tr>
					<td>/t</td>
					<td>以二进制的形式打印出整数。</td>
			</tr>
			<tr>
					<td>/f</td>
					<td>以浮点数的形式打印变量或表达式的值。</td>
			</tr>
			<tr>
					<td>/c</td>
					<td>以字符形式打印变量或表达式的值。</td>
			</tr>
	</tbody>
</table>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) p i       # 10进制
</span></span><span class="line"><span class="cl">$5 = 3
</span></span><span class="line"><span class="cl">(gdb) p/x i     # 16进制
</span></span><span class="line"><span class="cl">$6 = 0x3
</span></span><span class="line"><span class="cl">(gdb) p/o i     # 8进制
</span></span><span class="line"><span class="cl">$7 = 03
</span></span></code></pre></div><h3 id="打印地址值">打印地址值</h3>
<p>表示从内存地址 0x54320 读取内容，h 表示以双字节为单位，3 表示输出 3 个单位，u 表示按照十六进制显示。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) x/3uh 0x54320 
</span></span></code></pre></div><p>查看当前程序栈的内容：x/10x $sp–&gt;打印 stack 的前 10 个元素
查看当前程序栈的信息：info frame&mdash;-list general info about the frame
查看当前程序栈的参数：info args—lists arguments to the function
查看当前程序栈的局部变量：info locals—list variables stored in the frame
查看当前寄存器的值：info registers(不包括浮点寄存器)</p>
<h3 id="ptype-打印变量类型">ptype 打印变量类型</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) ptype i
</span></span><span class="line"><span class="cl">type = int
</span></span><span class="line"><span class="cl">(gdb) ptype array[i]
</span></span><span class="line"><span class="cl">type = int
</span></span><span class="line"><span class="cl">(gdb) ptype array
</span></span><span class="line"><span class="cl">type = int [12]
</span></span></code></pre></div><h3 id="display-跟踪显示变量">display 跟踪显示变量</h3>
<p><code>print</code>命令可以打印出变量的值，但是只是一次性的。如果我们想要跟踪某个变量的变化，可以使用<code>display</code>命令，每当程序在断点处停下，都会打印出跟踪的变量值。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) display 
</span></span></code></pre></div><p><code>info display</code>查看已跟踪的变量，<code>delete display</code>取消跟踪显示变量。</p>
<h3 id="step-执行一行代码">step 执行一行代码</h3>
<p>执行一行代码，如果改行代码是函数，将进入函数内部。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) s
</span></span></code></pre></div><h3 id="finish-跳出函数">finish 跳出函数</h3>
<p>如果通过<code>s</code>单步调试进入到函数内部，想要跳出这个函数体，可以执行 <code>finish</code>命令。如果想要跳出函数体必须要<strong>保证函数体内不能有有效断点</strong>，否则无法跳出。</p>
<h3 id="next-执行一行代码">next 执行一行代码</h3>
<p><code>next</code> 命令和 <code>step</code> 命令功能是相似的，只是在使用 <code>next</code> 调试程序的时候不会进入到函数体内部，<code>next</code> 可以缩写为 <code>n</code>。</p>
<h3 id="until-跳出循环体">until 跳出循环体</h3>
<p>通过 until 命令可以直接跳出某个循环体，这样就能提高调试效率了。如果想直接从循环体中跳出，必须要保证，<strong>要跳出的循环体内部不能有有效的断点</strong>，<strong>必须要在循环体的开始 / 结束行执行该命令</strong>。</p>
<h2 id="layout-分割窗口边调试边看源码">layout 分割窗口，边调试边看源码</h2>
<h3 id="layout-src">layout src</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153452.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153452.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="layout-asm">layout asm</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153520.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153520.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="layout-split">layout split</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153555.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153555.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="远程调试">远程调试</h2>
<h3 id="-s--s"><code>-s -S</code></h3>
<p><code>-s</code>启动<code>gdb server</code>，默认端口号为 1234
<code>-S</code>让程序在<code>_start</code>处停下。</p>
]]></content:encoded>
    </item>
    <item>
      <title>oh-my-zsh 让你的终端更加顺手（眼）</title>
      <link>https://lifeislife.cn/posts/oh-my-zsh%E8%AE%A9%E4%BD%A0%E7%9A%84%E7%BB%88%E7%AB%AF%E6%9B%B4%E5%8A%A0%E9%A1%BA%E6%89%8B%E7%9C%BC/</link>
      <pubDate>Sun, 29 Aug 2021 09:56:21 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/oh-my-zsh%E8%AE%A9%E4%BD%A0%E7%9A%84%E7%BB%88%E7%AB%AF%E6%9B%B4%E5%8A%A0%E9%A1%BA%E6%89%8B%E7%9C%BC/</guid>
      <description>&lt;h2 id=&#34;效果&#34;&gt;效果&lt;/h2&gt;
&lt;p&gt;主题：evan&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-36-00-26c3a41581cb4dc000d8c78d6ca8a8ce-20220911123600-4f3a26.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-36-00-26c3a41581cb4dc000d8c78d6ca8a8ce-20220911123600-4f3a26.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;主题：dallas&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-36-51-167fdec4a32cab8991e86880c5f8ca19-20220911123650-efd6fd.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-36-51-167fdec4a32cab8991e86880c5f8ca19-20220911123650-efd6fd.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;主题：robbyrussell&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-37-28-73012302d8cccf379a5f7664265e5c26-20220911123727-adbe5e.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-37-28-73012302d8cccf379a5f7664265e5c26-20220911123727-adbe5e.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;如果原先其他电脑安装过&#34;&gt;如果原先其他电脑安装过&lt;/h2&gt;
&lt;p&gt;把&lt;code&gt;.oh-my-zsh&lt;/code&gt;整个文件夹，&lt;code&gt;.zshrc&lt;/code&gt;，&lt;code&gt;.zsh_history&lt;/code&gt;复制到&lt;code&gt;/home/user/&lt;/code&gt;目录；&lt;/p&gt;
&lt;p&gt;安装&lt;code&gt;zsh&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;sudo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;apt&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;install&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;zsh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;切换&lt;code&gt;shell&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;chsh&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bin&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zsh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;~/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zshrc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;即可使用。所有配置都会和原先一样。&lt;/p&gt;
&lt;h2 id=&#34;如果是新安装&#34;&gt;如果是新安装&lt;/h2&gt;
&lt;p&gt;官方方法，&lt;code&gt;curl&lt;/code&gt;和&lt;code&gt;wget&lt;/code&gt;二选一即可&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应该也有人和我一样，可能会遇到连接 GitHub 失败的问题，要不就是 SSL 验证失败，要不就是连接无响应。可以更换下面的方法。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 先下载
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;## 再替换
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重启终端即可成功。&lt;/p&gt;
&lt;p&gt;如果无法访问 GitHub，其实&lt;code&gt;oh-my-zsh&lt;/code&gt;并不需要安装，完整的工程就是&lt;code&gt;oh-my-zsh&lt;/code&gt;本体，只要想办法把整个工程下载下来，并重命名为&lt;code&gt;oh-my-zsh&lt;/code&gt;即可。所以找找 gitee 有没有相关工程。这也是为什么从旧电脑里直接复制&lt;code&gt;.oh-my-zsh&lt;/code&gt;就能用的原因。&lt;/p&gt;
&lt;h2 id=&#34;插件安装&#34;&gt;插件安装&lt;/h2&gt;
&lt;h3 id=&#34;自动补全命令&#34;&gt;自动补全命令&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;plugins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        zsh-autosuggestions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;彩色ls&#34;&gt;彩色ls&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/09/08/8b288e971890f861c9c8dfabc88bafdc.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/09/08/8b288e971890f861c9c8dfabc88bafdc.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install lsd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果没有软件包，说明系统版本老旧，可以直接前往&lt;code&gt;https://github.com/lsd-rs/lsd/releases&lt;/code&gt;下载二进制包安装：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo dpkg -i lsd-musl_1.1.5_amd64.deb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;添加别名：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ls&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;lsd&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ls -l&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ll&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ls -al&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;la&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ls -a&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;lt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ls --tree&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;命令行命令高亮&#34;&gt;命令行命令高亮&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/zdharma-continuum/fast-syntax-highlighting.git ~/.oh-my-zsh/custom/plugins/fast-syntax-highlighting
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;plugins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        fast-syntax-highlighting
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;别名提示纠正&#34;&gt;别名提示纠正&lt;/h3&gt;
&lt;p&gt;如果命令有缩写别名，提示下次使用建议的别名。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/MichaelAquilina/zsh-you-should-use.git  ~/.oh-my-zsh/custom/plugins/you-should-use
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;plugins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        extract
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        sudo
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        z
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        thefuck
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        zsh-autosuggestions
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        you-should-use
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        fast-syntax-highlighting
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;
&lt;h3 id=&#34;oh-my-zshsh-parse-error-near-&#34;&gt;oh-my-zsh.sh parse error near `&amp;laquo;&amp;lt;&#39;&lt;/h3&gt;
&lt;p&gt;一般是在更新&lt;code&gt;oh-my-zsh&lt;/code&gt;时出现，因为更新相当于就是从远程拉取了内容，可能本地的&lt;code&gt;oh-my-zsh.sh&lt;/code&gt;脚本自己做了修改与远程冲突了。只要退回上个版本，重新拉取就可以了。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$ZSH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git reset --hard HEAD^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git pull --rebase
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果本地修改了一些内容需要保留，可以打开&lt;code&gt;oh-my-zsh.sh&lt;/code&gt;看看冲突在哪，自己做个备份，保存一下。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="效果">效果</h2>
<p>主题：evan</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-36-00-26c3a41581cb4dc000d8c78d6ca8a8ce-20220911123600-4f3a26.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-36-00-26c3a41581cb4dc000d8c78d6ca8a8ce-20220911123600-4f3a26.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>主题：dallas</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-36-51-167fdec4a32cab8991e86880c5f8ca19-20220911123650-efd6fd.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-36-51-167fdec4a32cab8991e86880c5f8ca19-20220911123650-efd6fd.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>主题：robbyrussell</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-37-28-73012302d8cccf379a5f7664265e5c26-20220911123727-adbe5e.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2022/09/11/12-37-28-73012302d8cccf379a5f7664265e5c26-20220911123727-adbe5e.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="如果原先其他电脑安装过">如果原先其他电脑安装过</h2>
<p>把<code>.oh-my-zsh</code>整个文件夹，<code>.zshrc</code>，<code>.zsh_history</code>复制到<code>/home/user/</code>目录；</p>
<p>安装<code>zsh</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="n">sudo</span> <span class="n">apt</span> <span class="n">install</span> <span class="n">zsh</span>
</span></span></code></pre></div><p>切换<code>shell</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="n">chsh</span> <span class="o">-</span><span class="n">s</span> <span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">zsh</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C++" data-lang="C++"><span class="line"><span class="cl"><span class="n">source</span> <span class="o">~/</span><span class="p">.</span><span class="n">zshrc</span>
</span></span></code></pre></div><p>即可使用。所有配置都会和原先一样。</p>
<h2 id="如果是新安装">如果是新安装</h2>
<p>官方方法，<code>curl</code>和<code>wget</code>二选一即可</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
</span></span><span class="line"><span class="cl">wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh
</span></span></code></pre></div><p>应该也有人和我一样，可能会遇到连接 GitHub 失败的问题，要不就是 SSL 验证失败，要不就是连接无响应。可以更换下面的方法。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl"># 先下载
</span></span><span class="line"><span class="cl">git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh
</span></span><span class="line"><span class="cl">## 再替换
</span></span><span class="line"><span class="cl">cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc
</span></span></code></pre></div><p>重启终端即可成功。</p>
<p>如果无法访问 GitHub，其实<code>oh-my-zsh</code>并不需要安装，完整的工程就是<code>oh-my-zsh</code>本体，只要想办法把整个工程下载下来，并重命名为<code>oh-my-zsh</code>即可。所以找找 gitee 有没有相关工程。这也是为什么从旧电脑里直接复制<code>.oh-my-zsh</code>就能用的原因。</p>
<h2 id="插件安装">插件安装</h2>
<h3 id="自动补全命令">自动补全命令</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">plugins</span><span class="o">=(</span>
</span></span><span class="line"><span class="cl">        zsh-autosuggestions
</span></span><span class="line"><span class="cl">        <span class="o">)</span>
</span></span></code></pre></div><h3 id="彩色ls">彩色ls</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/09/08/8b288e971890f861c9c8dfabc88bafdc.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img//2024/09/08/8b288e971890f861c9c8dfabc88bafdc.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt install lsd
</span></span></code></pre></div><p>如果没有软件包，说明系统版本老旧，可以直接前往<code>https://github.com/lsd-rs/lsd/releases</code>下载二进制包安装：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo dpkg -i lsd-musl_1.1.5_amd64.deb
</span></span></code></pre></div><p>添加别名：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">ls</span><span class="o">=</span><span class="s1">&#39;lsd&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">l</span><span class="o">=</span><span class="s2">&#34;ls -l&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">ll</span><span class="o">=</span><span class="s1">&#39;ls -al&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">la</span><span class="o">=</span><span class="s1">&#39;ls -a&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">lt</span><span class="o">=</span><span class="s1">&#39;ls --tree&#39;</span>
</span></span></code></pre></div><h3 id="命令行命令高亮">命令行命令高亮</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/zdharma-continuum/fast-syntax-highlighting.git ~/.oh-my-zsh/custom/plugins/fast-syntax-highlighting
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">plugins</span><span class="o">=(</span>
</span></span><span class="line"><span class="cl">        fast-syntax-highlighting
</span></span><span class="line"><span class="cl">        <span class="o">)</span>
</span></span></code></pre></div><h3 id="别名提示纠正">别名提示纠正</h3>
<p>如果命令有缩写别名，提示下次使用建议的别名。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/MichaelAquilina/zsh-you-should-use.git  ~/.oh-my-zsh/custom/plugins/you-should-use
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">plugins</span><span class="o">=(</span>
</span></span><span class="line"><span class="cl">        git
</span></span><span class="line"><span class="cl">        extract
</span></span><span class="line"><span class="cl">        sudo
</span></span><span class="line"><span class="cl">        z
</span></span><span class="line"><span class="cl">        thefuck
</span></span><span class="line"><span class="cl">        zsh-autosuggestions
</span></span><span class="line"><span class="cl">        you-should-use
</span></span><span class="line"><span class="cl">        fast-syntax-highlighting
</span></span><span class="line"><span class="cl">        <span class="o">)</span>
</span></span></code></pre></div><h2 id="问题">问题</h2>
<h3 id="oh-my-zshsh-parse-error-near-">oh-my-zsh.sh parse error near `&laquo;&lt;'</h3>
<p>一般是在更新<code>oh-my-zsh</code>时出现，因为更新相当于就是从远程拉取了内容，可能本地的<code>oh-my-zsh.sh</code>脚本自己做了修改与远程冲突了。只要退回上个版本，重新拉取就可以了。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="nv">$ZSH</span>
</span></span><span class="line"><span class="cl">git reset --hard HEAD^
</span></span><span class="line"><span class="cl">git pull --rebase
</span></span></code></pre></div><p>如果本地修改了一些内容需要保留，可以打开<code>oh-my-zsh.sh</code>看看冲突在哪，自己做个备份，保存一下。</p>
]]></content:encoded>
    </item>
    <item>
      <title>VSCode 单步调试 QEMU</title>
      <link>https://lifeislife.cn/posts/vscode%E5%8D%95%E6%AD%A5%E8%B0%83%E8%AF%95qemu/</link>
      <pubDate>Tue, 24 Aug 2021 19:24:08 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/vscode%E5%8D%95%E6%AD%A5%E8%B0%83%E8%AF%95qemu/</guid>
      <description>&lt;p&gt;了解了如何在&lt;a href=&#34;https://dunky-z.github.io/2021/08/23/VSCode%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/&#34;&gt;VSCode 中调试程序&lt;/a&gt;，接下来我们在 VSCode 中搭建调试 QEMU 的环境。&lt;/p&gt;
&lt;h2 id=&#34;配置&#34;&gt;配置&lt;/h2&gt;
&lt;p&gt;首先我们需要&lt;a href=&#34;https://dunky-z.github.io/2021/07/23/QEMU%E5%88%9D%E8%AF%86/&#34;&gt;下载和编译 QEMU 源码&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./configure --enable-debug --target-list=riscv32-softmmu,riscv32-linux-user --enable-kvm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一定要加上&lt;code&gt;--enable-debug&lt;/code&gt;，编译出的程序才带有调试信息，不用设置安装路径，编译时会自动在 qemu 文件夹下自动创建一个&lt;code&gt;build&lt;/code&gt;文件夹，编译后的程序也在&lt;code&gt;build&lt;/code&gt;文件夹下。&lt;/p&gt;
&lt;p&gt;用 VSCode 打开&lt;code&gt;qemu-6.X.X&lt;/code&gt;文件夹，&lt;code&gt;Ctrl+Shift+D&lt;/code&gt;打开调试配置。如果参考过&lt;a href=&#34;https://dunky-z.github.io/2021/08/23/VSCode%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/&#34;&gt;VSCode 中调试程序&lt;/a&gt;这篇文章，接下来就很容易。我们只需要将&lt;code&gt;launch.jason&lt;/code&gt;文件中的&lt;code&gt;program&lt;/code&gt;属性改为&lt;code&gt;${workspaceFolder}/build/qemu-system-riscv32&lt;/code&gt;即可。&lt;/p&gt;
&lt;h2 id=&#34;调试&#34;&gt;调试&lt;/h2&gt;
&lt;p&gt;打开&lt;code&gt;qemu-6.X.X/softmmu/main.c&lt;/code&gt;文件，在&lt;code&gt;main&lt;/code&gt;函数入口处打上断点，即可开始调试。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824194442.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824194442.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;现在只需要点击屏幕上的图标，就可以快速的进行单步调试。&lt;/p&gt;
&lt;p&gt;如果需要进行命令行操作，在屏幕下方打开&lt;code&gt;DEBUG CONSOLE&lt;/code&gt;，输入&lt;code&gt;-exec+正常命令行下的命令&lt;/code&gt;即可在命令行中进行更多的调试。如查看断点信息&lt;code&gt;-exec info breakpoints&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824201427.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824201427.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>了解了如何在<a href="https://dunky-z.github.io/2021/08/23/VSCode%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/">VSCode 中调试程序</a>，接下来我们在 VSCode 中搭建调试 QEMU 的环境。</p>
<h2 id="配置">配置</h2>
<p>首先我们需要<a href="https://dunky-z.github.io/2021/07/23/QEMU%E5%88%9D%E8%AF%86/">下载和编译 QEMU 源码</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">./configure --enable-debug --target-list=riscv32-softmmu,riscv32-linux-user --enable-kvm
</span></span></code></pre></div><p>一定要加上<code>--enable-debug</code>，编译出的程序才带有调试信息，不用设置安装路径，编译时会自动在 qemu 文件夹下自动创建一个<code>build</code>文件夹，编译后的程序也在<code>build</code>文件夹下。</p>
<p>用 VSCode 打开<code>qemu-6.X.X</code>文件夹，<code>Ctrl+Shift+D</code>打开调试配置。如果参考过<a href="https://dunky-z.github.io/2021/08/23/VSCode%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/">VSCode 中调试程序</a>这篇文章，接下来就很容易。我们只需要将<code>launch.jason</code>文件中的<code>program</code>属性改为<code>${workspaceFolder}/build/qemu-system-riscv32</code>即可。</p>
<h2 id="调试">调试</h2>
<p>打开<code>qemu-6.X.X/softmmu/main.c</code>文件，在<code>main</code>函数入口处打上断点，即可开始调试。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824194442.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824194442.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>现在只需要点击屏幕上的图标，就可以快速的进行单步调试。</p>
<p>如果需要进行命令行操作，在屏幕下方打开<code>DEBUG CONSOLE</code>，输入<code>-exec+正常命令行下的命令</code>即可在命令行中进行更多的调试。如查看断点信息<code>-exec info breakpoints</code></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824201427.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824201427.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>Qt 模仿登录界面-页面反转效果</title>
      <link>https://lifeislife.cn/posts/qt%E6%A8%A1%E4%BB%BF%E7%99%BB%E5%BD%95%E7%95%8C%E9%9D%A2-%E9%A1%B5%E9%9D%A2%E5%8F%8D%E8%BD%AC%E6%95%88%E6%9E%9C/</link>
      <pubDate>Tue, 24 Aug 2021 13:55:37 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qt%E6%A8%A1%E4%BB%BF%E7%99%BB%E5%BD%95%E7%95%8C%E9%9D%A2-%E9%A1%B5%E9%9D%A2%E5%8F%8D%E8%BD%AC%E6%95%88%E6%9E%9C/</guid>
      <description>&lt;p&gt;设置一个旋转效果，将登录界面旋转翻个面，设置一些网络参数。&lt;/p&gt;
&lt;h2 id=&#34;效果&#34;&gt;效果&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826100416.gif&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826100416.gif&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;网络参数设置界面布局&#34;&gt;网络参数设置界面布局&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824144033.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824144033.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;网络参数设置界面&#34;&gt;网络参数设置界面&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//loginnetsetwindow.cpp
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//初始化标题
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LoginNetSetWindow&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initMyTitle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_titleBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_titleBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raise&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_titleBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setBackgroundColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_titleBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setButtonType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MIN_BUTTON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_titleBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setTitleWidth&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_titleBar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setMoveParentWindowFlag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LoginNetSetWindow&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;QLabel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pBack&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QLabel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;QMovie&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;movie&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QMovie&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;movie&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setFileName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;:/Resources/NetSetWindow/headBack.gif&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;pBack&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setMovie&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;movie&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;movie&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;pBack&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;move&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ui&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pButtonOk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;clicked&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ui&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pButtonCancel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;clicked&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ui&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;comboBoxNetType&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addItem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QStringLiteral&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;不使用代理&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;ui&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;comboBoxServerType&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addItem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QStringLiteral&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;不使用高级选项&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LoginNetSetWindow&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;paintEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QPaintEvent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 绘制背景图;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;QPainter&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;QPainterPath&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathBack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;pathBack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setFillRule&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Qt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WindingFill&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;pathBack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addRoundedRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setRenderHint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QPainter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Antialiasing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fillPath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pathBack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QBrush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;235&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;242&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;249&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;QPainterPath&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pathBottom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;pathBottom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setFillRule&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Qt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WindingFill&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;pathBottom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addRoundedRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;300&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;300&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setRenderHint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QPainter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Antialiasing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fillPath&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pathBottom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QBrush&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;205&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;226&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;242&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setPen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QPen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;160&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;175&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;189&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;drawRoundedRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QRect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;initMyTitle()&lt;/code&gt;就不多说了，和正面登录界面差不多。&lt;/p&gt;
&lt;h3 id=&#34;qpainterpath类&#34;&gt;&lt;code&gt;QPainterPath&lt;/code&gt;类&lt;/h3&gt;
&lt;p&gt;它是由一些图形如曲线、矩形、椭圆组成的对象。主要的用途是，能保存已经绘制好的图形。实现图形元素的构造和复用；图形状只需创建一次，然后调用&lt;code&gt;QPainter::drawPath()&lt;/code&gt; 函数多次绘制。&lt;code&gt;painterpath&lt;/code&gt;可以加入闭合或不闭合的图形 ( 如：矩形、椭圆和曲线) 。&lt;code&gt;QPainterPath&lt;/code&gt; 可用于填充，描边，clipping。&lt;/p&gt;
&lt;h4 id=&#34;setfillrule设置填充模式&#34;&gt;&lt;code&gt;setFillRule()&lt;/code&gt;设置填充模式&lt;/h4&gt;
&lt;p&gt;不是很理解
&lt;a href=&#34;https://doc.qt.io/qt-5/qt.html#FillRule-enum&#34;&gt;https://doc.qt.io/qt-5/qt.html#FillRule-enum&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&#34;addroundedrectqrect0-0-this-width-this-height-3-3圆角矩形&#34;&gt;&lt;code&gt;addRoundedRect(QRect(0, 0, this-&amp;gt;width(), this-&amp;gt;height()), 3, 3)&lt;/code&gt;圆角矩形&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;QRect(0, 300, this-&amp;gt;width(), this-&amp;gt;height() - 300)&lt;/code&gt;设置了矩形的位置及大小&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(3,3)&lt;/code&gt;表示倒圆角的大小&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;setrenderhint开启反走样&#34;&gt;&lt;code&gt;setRenderHint()&lt;/code&gt;开启反走样&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;QPainter::Antialiasing&lt;/code&gt;           告诉绘图引擎应该在可能的情况下进行边的反锯齿绘制&lt;/li&gt;
&lt;li&gt;&lt;code&gt;QPainter::TextAntialiasing&lt;/code&gt;       尽可能的情况下文字的反锯齿绘制&lt;/li&gt;
&lt;li&gt;&lt;code&gt;QPainter::SmoothPixmapTransform&lt;/code&gt; 使用平滑的 pixmap 变换算法 (双线性插值算法),而不是近邻插值算&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;初始化旋转窗口&#34;&gt;初始化旋转窗口&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 初始化旋转的窗口;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RotateWidget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;initRotateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_loginWindow&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LoginWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 这里定义了两个信号，需要自己去发送信号;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLOT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;onRotateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;closeWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLOT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hideWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLOT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;onHideWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_loginNetSetWindow&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LoginNetSetWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginNetSetWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLOT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;onRotateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginNetSetWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;closeWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLOT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginNetSetWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hideWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLOT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;onHideWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addWidget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addWidget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginNetSetWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 这里宽和高都增加，是因为在旋转过程中窗口宽和高都会变化;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setFixedSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QSize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_loginWindow&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;m_loginWindow&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对正面和反面分别定义了信号槽，当对应的面接收到信号时，执行对应的动作。因为是旋转一百八十度，所以选择函数可以公用。&lt;/p&gt;
&lt;h2 id=&#34;旋转窗口&#34;&gt;旋转窗口&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824182705.gif&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824182705.gif&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 开始旋转窗口;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RotateWidget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;onRotateWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 如果窗口正在旋转，直接返回;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_isRoratingWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_isRoratingWindow&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_nextPageIndex&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;currentIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;currentIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;QPropertyAnimation&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateAnimation&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QPropertyAnimation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;rotateValue&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 设置旋转持续时间;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;rotateAnimation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setDuration&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1500&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 设置旋转角度变化趋势;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;rotateAnimation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setEasingCurve&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QEasingCurve&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;InCubic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 设置旋转角度范围;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;rotateAnimation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setStartValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;rotateAnimation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setEndValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;180&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateAnimation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;valueChanged&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QVariant&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLOT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;repaint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateAnimation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIGNAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;finished&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()),&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLOT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;onRotateFinished&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 隐藏当前窗口，通过不同角度的绘制来达到旋转的效果;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;currentWidget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hide&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;rotateAnimation&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 旋转结束;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RotateWidget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;onRotateFinished&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;m_isRoratingWindow&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;setCurrentWidget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;widget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_nextPageIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;repaint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;绘制旋转效果&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RotateWidget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;paintEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QPaintEvent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_isRoratingWindow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 小于 90 度时;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rotateValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;property&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;rotateValue&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;toInt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;90&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;QPixmap&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;rotatePixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;currentWidget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;currentWidget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotatePixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;QPainter&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setRenderHint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QPainter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Antialiasing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;QTransform&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;translate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Qt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;YAxis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setTransform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;drawPixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rotatePixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 大于 90 度时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;QPixmap&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;rotatePixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;widget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_nextPageIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;widget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;m_nextPageIndex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotatePixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;QPainter&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setRenderHint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;QPainter&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Antialiasing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;QTransform&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;translate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rotateValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;180&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Qt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;YAxis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setTransform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;transform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;painter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;drawPixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rotatePixmap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;QStackedWidget&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;paintEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;qpropertyanimation动画类&#34;&gt;&lt;code&gt;QPropertyAnimation&lt;/code&gt;动画类&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;QPropertyAnimation *rotateAnimation = new QPropertyAnimation(this, &amp;quot;rotateValue&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rotateValue&lt;/code&gt;就是这个动画的属性，我们这个动画中变化的就是旋转值，也就是旋转角度。这个属性名完全自己起，也可以改成&lt;code&gt;rotateAngle&lt;/code&gt;等等，或者说想做一个平移的动画，也可以取一个&lt;code&gt;moveDist&lt;/code&gt;等名字。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面这一串就是标准的一套动画流程&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    // 设置旋转持续时间;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    rotateAnimation-&amp;gt;setDuration(1000);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    // 设置旋转角度变化趋势;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    rotateAnimation-&amp;gt;setEasingCurve(QEasingCurve::InCubic);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    // 设置旋转角度范围;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    rotateAnimation-&amp;gt;setStartValue(0);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    rotateAnimation-&amp;gt;setEndValue(180);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    //开始动画
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    rotateAnimation-&amp;gt;start();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;paintevent绘图事件&#34;&gt;&lt;code&gt;paintEvent&lt;/code&gt;绘图事件&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;QtWidgets/QApplication&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;rotatewidget.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;QApplication&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;RotateWidget&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们&lt;code&gt;main&lt;/code&gt;函数得知，最开始显示的窗口就是&lt;code&gt;RotateWidget&lt;/code&gt;。在实例化一个&lt;code&gt;RotateWidget&lt;/code&gt;类后，进行了标题栏的初始化工作，然后开始执行&lt;code&gt;w.show()&lt;/code&gt;显示，但是此时窗口是不显示的。这是因为我们在&lt;code&gt;RotateWidget&lt;/code&gt;的构造函数中进行了设置不显示窗口。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setWindowFlags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Qt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FramelessWindowHint&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Qt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WindowStaysOnTopHint&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Qt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;WindowMinimizeButtonHint&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当运行到&lt;code&gt;return a.exec()&lt;/code&gt;时，Qt 会自动调用&lt;code&gt;void RotateWidget::paintEvent()&lt;/code&gt;。此时开始正式绘制窗口，但是因为我们还没哟点击登录页面的网络设置按钮，所以&lt;code&gt;m_isRoratingWindow=0&lt;/code&gt;。会调用父类的绘图事件，&lt;code&gt;QStackedWidget::paintEvent()&lt;/code&gt;，最后也就是&lt;code&gt;BaseWindow::paintEvent()&lt;/code&gt;。会将登录页面先绘制出来。&lt;/p&gt;
&lt;p&gt;当我们点击网络设置按钮时，&lt;code&gt;m_isRoratingWindow=1&lt;/code&gt;开始绘制旋转画面。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>设置一个旋转效果，将登录界面旋转翻个面，设置一些网络参数。</p>
<h2 id="效果">效果</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826100416.gif">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210826100416.gif" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="网络参数设置界面布局">网络参数设置界面布局</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824144033.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824144033.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="网络参数设置界面">网络参数设置界面</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">//loginnetsetwindow.cpp
</span></span></span><span class="line"><span class="cl"><span class="c1">//初始化标题
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">LoginNetSetWindow</span><span class="o">::</span><span class="n">initMyTitle</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_titleBar</span><span class="o">-&gt;</span><span class="n">move</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_titleBar</span><span class="o">-&gt;</span><span class="n">raise</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_titleBar</span><span class="o">-&gt;</span><span class="n">setBackgroundColor</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_titleBar</span><span class="o">-&gt;</span><span class="n">setButtonType</span><span class="p">(</span><span class="n">MIN_BUTTON</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_titleBar</span><span class="o">-&gt;</span><span class="n">setTitleWidth</span><span class="p">(</span><span class="k">this</span><span class="o">-&gt;</span><span class="n">width</span><span class="p">());</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_titleBar</span><span class="o">-&gt;</span><span class="n">setMoveParentWindowFlag</span><span class="p">(</span><span class="nb">false</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">LoginNetSetWindow</span><span class="o">::</span><span class="n">initWindow</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">QLabel</span><span class="o">*</span> <span class="n">pBack</span> <span class="o">=</span> <span class="k">new</span> <span class="n">QLabel</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">QMovie</span> <span class="o">*</span><span class="n">movie</span> <span class="o">=</span> <span class="k">new</span> <span class="n">QMovie</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="n">movie</span><span class="o">-&gt;</span><span class="n">setFileName</span><span class="p">(</span><span class="s">&#34;:/Resources/NetSetWindow/headBack.gif&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">pBack</span><span class="o">-&gt;</span><span class="n">setMovie</span><span class="p">(</span><span class="n">movie</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">movie</span><span class="o">-&gt;</span><span class="n">start</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="n">pBack</span><span class="o">-&gt;</span><span class="n">move</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">ui</span><span class="p">.</span><span class="n">pButtonOk</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">clicked</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">rotateWindow</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">ui</span><span class="p">.</span><span class="n">pButtonCancel</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">clicked</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">rotateWindow</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">    <span class="n">ui</span><span class="p">.</span><span class="n">comboBoxNetType</span><span class="o">-&gt;</span><span class="n">addItem</span><span class="p">(</span><span class="n">QStringLiteral</span><span class="p">(</span><span class="s">&#34;不使用代理&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">ui</span><span class="p">.</span><span class="n">comboBoxServerType</span><span class="o">-&gt;</span><span class="n">addItem</span><span class="p">(</span><span class="n">QStringLiteral</span><span class="p">(</span><span class="s">&#34;不使用高级选项&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">LoginNetSetWindow</span><span class="o">::</span><span class="n">paintEvent</span><span class="p">(</span><span class="n">QPaintEvent</span> <span class="o">*</span><span class="n">event</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 绘制背景图;
</span></span></span><span class="line"><span class="cl"> <span class="n">QPainter</span> <span class="nf">painter</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">QPainterPath</span> <span class="n">pathBack</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">pathBack</span><span class="p">.</span><span class="n">setFillRule</span><span class="p">(</span><span class="n">Qt</span><span class="o">::</span><span class="n">WindingFill</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">pathBack</span><span class="p">.</span><span class="n">addRoundedRect</span><span class="p">(</span><span class="n">QRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">width</span><span class="p">(),</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">height</span><span class="p">()),</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">painter</span><span class="p">.</span><span class="n">setRenderHint</span><span class="p">(</span><span class="n">QPainter</span><span class="o">::</span><span class="n">Antialiasing</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">painter</span><span class="p">.</span><span class="n">fillPath</span><span class="p">(</span><span class="n">pathBack</span><span class="p">,</span> <span class="n">QBrush</span><span class="p">(</span><span class="n">QColor</span><span class="p">(</span><span class="mi">235</span><span class="p">,</span> <span class="mi">242</span><span class="p">,</span> <span class="mi">249</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="n">QPainterPath</span> <span class="n">pathBottom</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">pathBottom</span><span class="p">.</span><span class="n">setFillRule</span><span class="p">(</span><span class="n">Qt</span><span class="o">::</span><span class="n">WindingFill</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">pathBottom</span><span class="p">.</span><span class="n">addRoundedRect</span><span class="p">(</span><span class="n">QRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">300</span><span class="p">,</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">width</span><span class="p">(),</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">height</span><span class="p">()</span> <span class="o">-</span> <span class="mi">300</span><span class="p">),</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">painter</span><span class="p">.</span><span class="n">setRenderHint</span><span class="p">(</span><span class="n">QPainter</span><span class="o">::</span><span class="n">Antialiasing</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">painter</span><span class="p">.</span><span class="n">fillPath</span><span class="p">(</span><span class="n">pathBottom</span><span class="p">,</span> <span class="n">QBrush</span><span class="p">(</span><span class="n">QColor</span><span class="p">(</span><span class="mi">205</span><span class="p">,</span> <span class="mi">226</span><span class="p">,</span> <span class="mi">242</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">painter</span><span class="p">.</span><span class="n">setPen</span><span class="p">(</span><span class="n">QPen</span><span class="p">(</span><span class="n">QColor</span><span class="p">(</span><span class="mi">160</span> <span class="p">,</span> <span class="mi">175</span> <span class="p">,</span> <span class="mi">189</span><span class="p">)));</span>
</span></span><span class="line"><span class="cl"> <span class="n">painter</span><span class="p">.</span><span class="n">drawRoundedRect</span><span class="p">(</span><span class="n">QRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">width</span><span class="p">(),</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">height</span><span class="p">()),</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>initMyTitle()</code>就不多说了，和正面登录界面差不多。</p>
<h3 id="qpainterpath类"><code>QPainterPath</code>类</h3>
<p>它是由一些图形如曲线、矩形、椭圆组成的对象。主要的用途是，能保存已经绘制好的图形。实现图形元素的构造和复用；图形状只需创建一次，然后调用<code>QPainter::drawPath()</code> 函数多次绘制。<code>painterpath</code>可以加入闭合或不闭合的图形 ( 如：矩形、椭圆和曲线) 。<code>QPainterPath</code> 可用于填充，描边，clipping。</p>
<h4 id="setfillrule设置填充模式"><code>setFillRule()</code>设置填充模式</h4>
<p>不是很理解
<a href="https://doc.qt.io/qt-5/qt.html#FillRule-enum">https://doc.qt.io/qt-5/qt.html#FillRule-enum</a></p>
<h4 id="addroundedrectqrect0-0-this-width-this-height-3-3圆角矩形"><code>addRoundedRect(QRect(0, 0, this-&gt;width(), this-&gt;height()), 3, 3)</code>圆角矩形</h4>
<ul>
<li><code>QRect(0, 300, this-&gt;width(), this-&gt;height() - 300)</code>设置了矩形的位置及大小</li>
<li><code>(3,3)</code>表示倒圆角的大小</li>
</ul>
<h3 id="setrenderhint开启反走样"><code>setRenderHint()</code>开启反走样</h3>
<ul>
<li><code>QPainter::Antialiasing</code>           告诉绘图引擎应该在可能的情况下进行边的反锯齿绘制</li>
<li><code>QPainter::TextAntialiasing</code>       尽可能的情况下文字的反锯齿绘制</li>
<li><code>QPainter::SmoothPixmapTransform</code> 使用平滑的 pixmap 变换算法 (双线性插值算法),而不是近邻插值算</li>
</ul>
<h2 id="初始化旋转窗口">初始化旋转窗口</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// 初始化旋转的窗口;
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">RotateWidget</span><span class="o">::</span><span class="n">initRotateWindow</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_loginWindow</span> <span class="o">=</span> <span class="k">new</span> <span class="n">LoginWindow</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 这里定义了两个信号，需要自己去发送信号;
</span></span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">m_loginWindow</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">rotateWindow</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SLOT</span><span class="p">(</span><span class="n">onRotateWindow</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">m_loginWindow</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">closeWindow</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SLOT</span><span class="p">(</span><span class="n">close</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">m_loginWindow</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">hideWindow</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SLOT</span><span class="p">(</span><span class="n">onHideWindow</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">m_loginNetSetWindow</span> <span class="o">=</span> <span class="k">new</span> <span class="n">LoginNetSetWindow</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">m_loginNetSetWindow</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">rotateWindow</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SLOT</span><span class="p">(</span><span class="n">onRotateWindow</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">m_loginNetSetWindow</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">closeWindow</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SLOT</span><span class="p">(</span><span class="n">close</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">m_loginNetSetWindow</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">hideWindow</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SLOT</span><span class="p">(</span><span class="n">onHideWindow</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">this</span><span class="o">-&gt;</span><span class="n">addWidget</span><span class="p">(</span><span class="n">m_loginWindow</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">this</span><span class="o">-&gt;</span><span class="n">addWidget</span><span class="p">(</span><span class="n">m_loginNetSetWindow</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1">// 这里宽和高都增加，是因为在旋转过程中窗口宽和高都会变化;
</span></span></span><span class="line"><span class="cl"> <span class="k">this</span><span class="o">-&gt;</span><span class="n">setFixedSize</span><span class="p">(</span><span class="n">QSize</span><span class="p">(</span><span class="n">m_loginWindow</span><span class="o">-&gt;</span><span class="n">width</span><span class="p">()</span> <span class="o">+</span> <span class="mi">20</span><span class="p">,</span> <span class="n">m_loginWindow</span><span class="o">-&gt;</span><span class="n">height</span><span class="p">()</span> <span class="o">+</span> <span class="mi">100</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>对正面和反面分别定义了信号槽，当对应的面接收到信号时，执行对应的动作。因为是旋转一百八十度，所以选择函数可以公用。</p>
<h2 id="旋转窗口">旋转窗口</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824182705.gif">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824182705.gif" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 开始旋转窗口;
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">RotateWidget</span><span class="o">::</span><span class="n">onRotateWindow</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 如果窗口正在旋转，直接返回;
</span></span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">m_isRoratingWindow</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_isRoratingWindow</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_nextPageIndex</span> <span class="o">=</span> <span class="p">(</span><span class="n">currentIndex</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="n">count</span><span class="p">()</span> <span class="o">?</span> <span class="mi">0</span> <span class="o">:</span> <span class="p">(</span><span class="n">currentIndex</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">QPropertyAnimation</span> <span class="o">*</span><span class="n">rotateAnimation</span> <span class="o">=</span> <span class="k">new</span> <span class="n">QPropertyAnimation</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="s">&#34;rotateValue&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 设置旋转持续时间;
</span></span></span><span class="line"><span class="cl"> <span class="n">rotateAnimation</span><span class="o">-&gt;</span><span class="n">setDuration</span><span class="p">(</span><span class="mi">1500</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 设置旋转角度变化趋势;
</span></span></span><span class="line"><span class="cl"> <span class="n">rotateAnimation</span><span class="o">-&gt;</span><span class="n">setEasingCurve</span><span class="p">(</span><span class="n">QEasingCurve</span><span class="o">::</span><span class="n">InCubic</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 设置旋转角度范围;
</span></span></span><span class="line"><span class="cl"> <span class="n">rotateAnimation</span><span class="o">-&gt;</span><span class="n">setStartValue</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">rotateAnimation</span><span class="o">-&gt;</span><span class="n">setEndValue</span><span class="p">(</span><span class="mi">180</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">rotateAnimation</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">valueChanged</span><span class="p">(</span><span class="n">QVariant</span><span class="p">)),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SLOT</span><span class="p">(</span><span class="n">repaint</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl"> <span class="n">connect</span><span class="p">(</span><span class="n">rotateAnimation</span><span class="p">,</span> <span class="n">SIGNAL</span><span class="p">(</span><span class="n">finished</span><span class="p">()),</span> <span class="k">this</span><span class="p">,</span> <span class="n">SLOT</span><span class="p">(</span><span class="n">onRotateFinished</span><span class="p">()));</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 隐藏当前窗口，通过不同角度的绘制来达到旋转的效果;
</span></span></span><span class="line"><span class="cl"> <span class="n">currentWidget</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">hide</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="n">rotateAnimation</span><span class="o">-&gt;</span><span class="n">start</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 旋转结束;
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">RotateWidget</span><span class="o">::</span><span class="n">onRotateFinished</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">m_isRoratingWindow</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">setCurrentWidget</span><span class="p">(</span><span class="n">widget</span><span class="p">(</span><span class="n">m_nextPageIndex</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">repaint</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">/</span> <span class="err">绘制旋转效果</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="n">RotateWidget</span><span class="o">::</span><span class="n">paintEvent</span><span class="p">(</span><span class="n">QPaintEvent</span> <span class="o">*</span><span class="n">event</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">m_isRoratingWindow</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 小于 90 度时;
</span></span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">rotateValue</span> <span class="o">=</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">property</span><span class="p">(</span><span class="s">&#34;rotateValue&#34;</span><span class="p">).</span><span class="n">toInt</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">rotateValue</span> <span class="o">&lt;=</span> <span class="mi">90</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">QPixmap</span> <span class="nf">rotatePixmap</span><span class="p">(</span><span class="n">currentWidget</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">            <span class="n">currentWidget</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">render</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rotatePixmap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">QPainter</span> <span class="nf">painter</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">painter</span><span class="p">.</span><span class="n">setRenderHint</span><span class="p">(</span><span class="n">QPainter</span><span class="o">::</span><span class="n">Antialiasing</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">QTransform</span> <span class="n">transform</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">transform</span><span class="p">.</span><span class="n">translate</span><span class="p">(</span><span class="n">width</span><span class="p">()</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">transform</span><span class="p">.</span><span class="n">rotate</span><span class="p">(</span><span class="n">rotateValue</span><span class="p">,</span> <span class="n">Qt</span><span class="o">::</span><span class="n">YAxis</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">painter</span><span class="p">.</span><span class="n">setTransform</span><span class="p">(</span><span class="n">transform</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">painter</span><span class="p">.</span><span class="n">drawPixmap</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">*</span> <span class="n">width</span><span class="p">()</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">rotatePixmap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 大于 90 度时
</span></span></span><span class="line"><span class="cl">        <span class="k">else</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">QPixmap</span> <span class="nf">rotatePixmap</span><span class="p">(</span><span class="n">widget</span><span class="p">(</span><span class="n">m_nextPageIndex</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">());</span>
</span></span><span class="line"><span class="cl">            <span class="n">widget</span><span class="p">(</span><span class="n">m_nextPageIndex</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">render</span><span class="p">(</span><span class="o">&amp;</span><span class="n">rotatePixmap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">QPainter</span> <span class="nf">painter</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">painter</span><span class="p">.</span><span class="n">setRenderHint</span><span class="p">(</span><span class="n">QPainter</span><span class="o">::</span><span class="n">Antialiasing</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">QTransform</span> <span class="n">transform</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">transform</span><span class="p">.</span><span class="n">translate</span><span class="p">(</span><span class="n">width</span><span class="p">()</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">transform</span><span class="p">.</span><span class="n">rotate</span><span class="p">(</span><span class="n">rotateValue</span> <span class="o">+</span> <span class="mi">180</span><span class="p">,</span> <span class="n">Qt</span><span class="o">::</span><span class="n">YAxis</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">painter</span><span class="p">.</span><span class="n">setTransform</span><span class="p">(</span><span class="n">transform</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="n">painter</span><span class="p">.</span><span class="n">drawPixmap</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">*</span> <span class="n">width</span><span class="p">()</span> <span class="o">/</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">rotatePixmap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">QStackedWidget</span><span class="o">::</span><span class="n">paintEvent</span><span class="p">(</span><span class="n">event</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="qpropertyanimation动画类"><code>QPropertyAnimation</code>动画类</h3>
<p><code>QPropertyAnimation *rotateAnimation = new QPropertyAnimation(this, &quot;rotateValue&quot;)</code></p>
<ul>
<li><code>rotateValue</code>就是这个动画的属性，我们这个动画中变化的就是旋转值，也就是旋转角度。这个属性名完全自己起，也可以改成<code>rotateAngle</code>等等，或者说想做一个平移的动画，也可以取一个<code>moveDist</code>等名字。</li>
</ul>
<p>下面这一串就是标准的一套动画流程</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">    // 设置旋转持续时间;
</span></span><span class="line"><span class="cl">    rotateAnimation-&gt;setDuration(1000);
</span></span><span class="line"><span class="cl">    // 设置旋转角度变化趋势;
</span></span><span class="line"><span class="cl">    rotateAnimation-&gt;setEasingCurve(QEasingCurve::InCubic);
</span></span><span class="line"><span class="cl">    // 设置旋转角度范围;
</span></span><span class="line"><span class="cl">    rotateAnimation-&gt;setStartValue(0);
</span></span><span class="line"><span class="cl">    rotateAnimation-&gt;setEndValue(180);
</span></span><span class="line"><span class="cl">    //开始动画
</span></span><span class="line"><span class="cl">    rotateAnimation-&gt;start();
</span></span></code></pre></div><h3 id="paintevent绘图事件"><code>paintEvent</code>绘图事件</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;QtWidgets/QApplication&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;rotatewidget.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">QApplication</span> <span class="n">a</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">RotateWidget</span> <span class="n">w</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">w</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">exec</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>我们<code>main</code>函数得知，最开始显示的窗口就是<code>RotateWidget</code>。在实例化一个<code>RotateWidget</code>类后，进行了标题栏的初始化工作，然后开始执行<code>w.show()</code>显示，但是此时窗口是不显示的。这是因为我们在<code>RotateWidget</code>的构造函数中进行了设置不显示窗口。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl">    <span class="k">this</span><span class="o">-&gt;</span><span class="n">setWindowFlags</span><span class="p">(</span><span class="n">Qt</span><span class="o">::</span><span class="n">FramelessWindowHint</span> <span class="o">|</span> 
</span></span><span class="line"><span class="cl">    <span class="n">Qt</span><span class="o">::</span><span class="n">WindowStaysOnTopHint</span> <span class="o">|</span> 
</span></span><span class="line"><span class="cl">    <span class="n">Qt</span><span class="o">::</span><span class="n">WindowMinimizeButtonHint</span><span class="p">);</span>
</span></span></code></pre></div><p>当运行到<code>return a.exec()</code>时，Qt 会自动调用<code>void RotateWidget::paintEvent()</code>。此时开始正式绘制窗口，但是因为我们还没哟点击登录页面的网络设置按钮，所以<code>m_isRoratingWindow=0</code>。会调用父类的绘图事件，<code>QStackedWidget::paintEvent()</code>，最后也就是<code>BaseWindow::paintEvent()</code>。会将登录页面先绘制出来。</p>
<p>当我们点击网络设置按钮时，<code>m_isRoratingWindow=1</code>开始绘制旋转画面。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 操作系统-系统初始化</title>
      <link>https://lifeislife.cn/posts/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E7%B3%BB%E7%BB%9F%E5%88%9D%E5%A7%8B%E5%8C%96/</link>
      <pubDate>Tue, 24 Aug 2021 09:45:57 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E7%B3%BB%E7%BB%9F%E5%88%9D%E5%A7%8B%E5%8C%96/</guid>
      <description>&lt;h2 id=&#34;系统初始化&#34;&gt;系统初始化&lt;/h2&gt;
&lt;h3 id=&#34;x86-架构概述&#34;&gt;x86 架构概述&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;CPU（Central Processing Unit）&lt;/strong&gt;：中央处理器，计算机所有设备都围绕它展开工作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;运算单元：只管算，例如做加法、做位移等等。但是，它不知道应该算哪些数据，运算结果应该放在哪里。&lt;/li&gt;
&lt;li&gt;数据单元：运算单元计算的数据如果每次都要经过总线，到内存里面现拿，这样就太慢了，所以就有了数据单元。数据单元包括 CPU 内部的缓存和寄存器组，空间很小，但是速度飞快，可以暂时存放数据和运算结果。&lt;/li&gt;
&lt;li&gt;控制单元：有了放数据的地方，也有了算的地方，还需要有个指挥到底做什么运算的地方，这就是控制单元。控制单元是一个统一的指挥中心，它可以获得下一条指令，然后执行这条指令。这个指令会指导运算单元取出数据单元中的某几个数据，计算出个结果，然后放在数据单元的某个地方。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;内存（Memory）&lt;/strong&gt;：CPU 本身不能保存大量数据，许多复杂的计算需要将中间结果保存下来就必须用到内存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总线（Bus）&lt;/strong&gt;：CPU 和其他设备连接，就靠总线，其实就是主板上密密麻麻的集成电路，这些东西组成了 CPU 和其他设备的高速通道。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;地址总线：传输地址数据（我想拿内存中哪个位置的数据）&lt;/li&gt;
&lt;li&gt;数据总线：传输真正的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总线就像 CPU 和内存之间的高速公路，总线多少位就类似高速公路多少个车道，但两种总线的位数意义不同。&lt;/p&gt;
&lt;p&gt;地址总线的位数决定了访问地址范围有多广，数据总线位数决定了一次能拿多少数据进来。那么 CPU 中总线的位数有没有标准呢？如果没有标准，那操作系统作为软件就很难办了，因为软件层没办法实现通用的运算逻辑。早期每家公司的 CPU 架构都不同，后来历史将 x86 平台推到了&lt;strong&gt;开放，统一，兼容&lt;/strong&gt;的位置。&lt;/p&gt;
&lt;h4 id=&#34;8086-架构图&#34;&gt;8086 架构图&lt;/h4&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721092854.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721092854.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数据单元：&lt;/strong&gt; 8086 处理器内部共有 8 个 16 位的通用寄存器，分别是 数据寄存器（AX、BX、CX、DX）、指针寄存器（SP、BP）、变址寄存器（SI、DI）。其中 AX、BX、CX、DX 可以分成两个 8 位的寄存器来使用，分别是 AH、AL、BH、BL、CH、CL、DH、DL，其中 H 就是 High（高位），L 就是 Low（低位）的意思。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;控制单元：&lt;/strong&gt; IP 寄存器（Instruction Pointer Register）就是指令指针寄存器，它指向代码段中下一条指令的位置。CPU 会根据它来不断地将指令从内存的代码段中，加载到 CPU 的指令队列中，然后交给运算单元去执行。&lt;/p&gt;
&lt;p&gt;如果需要切换进程呢？每个进程都分代码段和数据段，为了指向不同进程的地址空间，有四个 16 位的段寄存器，分别是 CS、DS、SS、ES。&lt;/p&gt;
&lt;p&gt;其中，&lt;strong&gt;CS&lt;/strong&gt; 就是代码段寄存器（Code Segment Register），通过它可以找到代码在内存中的位置；&lt;strong&gt;DS&lt;/strong&gt; 是数据段的寄存器（Data Segment Register），通过它可以找到数据在内存中的位置。&lt;strong&gt;SS&lt;/strong&gt; 是栈寄存器（Stack Register）。栈是程序运行中一个特殊的数据结构，数据的存取只能从一端进行，秉承后进先出的原则。&lt;strong&gt;ES&lt;/strong&gt;是扩展段寄存器（Extra Segment Register）顾名思义。&lt;/p&gt;
&lt;p&gt;如果 CPU 运算中需要加载内存中的数据，需要通过 DS 找到内存中的数据，加载到通用寄存器中，应该如何加载呢？对于一个段，有一个起始的地址，而段内的具体位置，我们称为&lt;strong&gt;偏移量（Offset）&lt;/strong&gt;。在 CS 和 DS 中都存放着一个段的起始地址。&lt;strong&gt;代码段的偏移量在 IP 寄存器中&lt;/strong&gt;，&lt;strong&gt;数据段的偏移量会放在通用寄存器中&lt;/strong&gt;。因为段寄存器都是 16 位的，而地址总线是 20 位的，所以通过 *&lt;em&gt;起始地址 &lt;em&gt;16+ 偏移量&lt;/em&gt;&lt;/em&gt; 的方式，将寻址位数都变成 20 位，也就是将 CS 和 DS 的值左移 4 位。&lt;/p&gt;
&lt;p&gt;对于只有 20 位地址总线的 8086 来说，寻址空间最大也就是$2^{20}=1\text{M}$，超过这个位置就访问不到了，一个段因为偏移量只有 16 位，所以一个段最大是$2^{16}=64\text{k}$。&lt;/p&gt;
&lt;h4 id=&#34;32-位处理器&#34;&gt;32 位处理器&lt;/h4&gt;
&lt;p&gt;随着计算机发展，内存越来越大，总线也越来越宽。在 32 位处理器中，有 32 根地址总线，可以访问 $2^{32}=4\text{G}$ 的内存。使用原来的模式肯定不行了，但是又不能完全抛弃原来的模式，因为这个架构是&lt;strong&gt;开放的&lt;/strong&gt;。那么在开发架构的基础上如何保持兼容呢？&lt;/p&gt;
&lt;p&gt;首先，通用寄存器有扩展，可以将 8 个 16 位的扩展到 8 个 32 位的，但是依然可以保留 16 位的和 8 位的使用方式。其中，指向下一条指令的指令指针寄存器 IP，就会扩展成 32 位的，同样也兼容 16 位的。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721103205.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721103205.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;段寄存器改动较大，新的段寄存器都改成了 32 位的，每个寄存器又分为&lt;strong&gt;段描述符缓存器（Segment Descriptor）&lt;/strong&gt;，和&lt;strong&gt;段选择子寄存器（Selector）&lt;/strong&gt; ,现在的段寄存器不在是段的起始地址，段的起始地址保存在表格一样的段描述符缓冲器中，段选择子寄存器保存地址在段描述符缓存器中的哪一项。这样，将一个从段寄存器直接拿到的段起始地址，就变成了&lt;strong&gt;先间接地从段寄存器找到表格中的一项，再从表格中的一项中拿到段起始地址。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;虽然现在的这种模式和之前的模式不兼容，但是后面这种模式灵活的非常高，可以保持一直兼容下去。在 32 位的系统架构下，将前一种模式称为&lt;strong&gt;实模式（Real Pattern）&lt;/strong&gt;，后一种模式称为&lt;strong&gt;保护模式（Protected Pattern）&lt;/strong&gt; 。当系统刚刚启动的时候，CPU 是处于实模式的，这个时候和原来的模式是兼容的。也就是说，哪怕你买了 32 位的 CPU，也支持在原来的模式下运行。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721104550.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721104550.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;汇编命令学习
mov,
call, jmp, int, ret, add, or, xor, shl, shr, push, pop, inc, dec, sub, cmp。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;bios-与-bootloader&#34;&gt;BIOS 与 BootLoader&lt;/h3&gt;
&lt;p&gt;BIOS：基本输入输出系统&lt;/p&gt;
&lt;p&gt;ROM：只读存储器&lt;/p&gt;
&lt;p&gt;RAM：随机存取存储器&lt;/p&gt;
&lt;p&gt;在我们按下电脑电源键的那一刻，主板就加电了，CPU 就要开始执行指令了，但是刚开始操作系统都没，CPU 执行什么指令呢？这就有了&lt;code&gt;BIOS&lt;/code&gt;，它相当于一个指导手册，告诉 CPU 接下来要干啥。&lt;/p&gt;
&lt;p&gt;刚开机时，系统初始化代码从 ROM 读取，将 &lt;code&gt;CS&lt;/code&gt; 设置为 &lt;code&gt;0xFFFF&lt;/code&gt;，将 &lt;code&gt;IP&lt;/code&gt; 设置为 &lt;code&gt;0x0000&lt;/code&gt;，所以第一条指令就会指向 &lt;code&gt;0xFFFF0&lt;/code&gt;，初始化完成后确定访问指令位置。&lt;/p&gt;
&lt;p&gt;接下来 BIOS 会检查各个硬件是否正常，检测内容显卡等关键部件的存在于工作状态，设备初始化，执行系统 BIOS 进行系统检测，更新 CMOS 中的扩展系统配置数据 ESCD。这期间也会建立中断向量表和中断服务程序，因为要使用键盘鼠标都需要中断进行。&lt;/p&gt;
&lt;p&gt;下一步 BIOS 就得要找操作系统了，操作系统一般安装在硬盘上，但是 BIOS 得先找到启动盘，启动盘一般安装在第一个扇区，占 512 字节，会包含启动的相关代码。在 Linux 中，可以通过&lt;code&gt;Grub2&lt;/code&gt;配置这些代码。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grub2-mkconfig -o /boot/grub2/grub.cfg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;grub2&lt;/code&gt;第一个要安装的就是&lt;code&gt;boot.img&lt;/code&gt;。它由 &lt;code&gt;boot.S&lt;/code&gt;编译而成，一共 &lt;code&gt;512&lt;/code&gt; 字节，正式安装到启动盘的第一个扇区。这个扇区通常称为&lt;code&gt;MBR&lt;/code&gt;（Master Boot Record，主引导记录 / 扇区）。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BIOS&lt;/code&gt; 完成任务后，会将 &lt;code&gt;boot.img&lt;/code&gt; 从硬盘加载到内存中的 &lt;code&gt;0x7c00&lt;/code&gt;来运行。&lt;/p&gt;
&lt;p&gt;由于 &lt;code&gt;512&lt;/code&gt; 个字节实在有限，&lt;code&gt;boot.img&lt;/code&gt; 做不了太多的事情。它能做的最重要的一个事情就是加载&lt;code&gt;grub2&lt;/code&gt; 的另一个镜像 &lt;code&gt;core.img&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;core.img&lt;/code&gt; 由&lt;code&gt;lzma_decompress.img&lt;/code&gt;、&lt;code&gt;diskboot.img&lt;/code&gt;、&lt;code&gt;kernel.img&lt;/code&gt; 和一系列的模块组成，功能比较丰富，能做很多事情。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;boot.img&lt;/code&gt; 先加载的是 &lt;code&gt;core.img&lt;/code&gt; 的第一个扇区。如果从硬盘启动的话，这个扇区里面是&lt;code&gt;diskboot.img&lt;/code&gt;，对应的代码是 &lt;code&gt;diskboot.S&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;boot.img&lt;/code&gt; 将控制权交给 &lt;code&gt;diskboot.img&lt;/code&gt; 后，&lt;code&gt;diskboot.img&lt;/code&gt; 的任务就是将&lt;code&gt;core.img&lt;/code&gt; 的其他部分加载进来，先是解压缩程序 &lt;code&gt;lzma_decompress.img&lt;/code&gt;，再往下是 &lt;code&gt;kernel.img&lt;/code&gt;，最后是各个模块&lt;code&gt;module&lt;/code&gt;对应的映像。这里需要注意，它不是 Linux 的内核，而是&lt;code&gt;grub&lt;/code&gt; 的内核。&lt;/p&gt;
&lt;p&gt;在这之前，我们所有遇到过的程序都非常非常小，完全可以在实模式下运行，但是随着我们加载的东西越来越大，实模式这&lt;code&gt;1M&lt;/code&gt; 的地址空间实在放不下了，所以在真正的解压缩之前，&lt;code&gt;lzma_decompress.img&lt;/code&gt; 做了一个重要的决定，就是调用 &lt;code&gt;real_to_prot&lt;/code&gt;，切换到&lt;strong&gt;保护模式&lt;/strong&gt;，这样就能在更大的寻址空间里面，加载更多的东西。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BIOS&lt;/code&gt;将加载程序从硬盘的引导扇区加载到指定位置，再跳转到指定位置，将控制权转交给加载程序。加载程序将操作系统代码读取到内存，并将控制权转到操作系统。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Q：BIOS-操作系统，中间经过加载程序。为何不直接读取？
A：磁盘文件系统多种多样，硬盘出厂时不能限制只能用一种文件系统，而 BIOS 也不能加上识别所有文件系统的代码。所有为了灵活性只读取磁盘的一块，由加载程序来识别磁盘的文件系统。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;切换到保护模式后，将会做以下这些事，大多数都与内存访问方式有关。&lt;/p&gt;
&lt;p&gt;首先&lt;strong&gt;启动分段&lt;/strong&gt;，就是在内存里面&lt;strong&gt;建立段描述符表&lt;/strong&gt;，将寄存器里面的段寄存器变成段选择子，指向某个段描述符，这样就能实现不同进程的切换了。&lt;/p&gt;
&lt;p&gt;接着是&lt;strong&gt;启动分页&lt;/strong&gt;。能够管理的内存变大了，就需要将内存分成相等大小的块。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;打开 Gate20&lt;/strong&gt;，也就是第 21 根地址线的控制线。因为在实模式 8086 下，一共就 20 根地址线，最大访问&lt;code&gt;1M&lt;/code&gt;的地址空间。切换保护模式的函数&lt;code&gt;DATA32 call real_to_prot&lt;/code&gt;会打开&lt;code&gt;Gate A20&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;现在好了，有的是空间了。接下来我们要对压缩过的 &lt;strong&gt;kernel.img 进行解压缩&lt;/strong&gt;，然后跳转到 &lt;code&gt;kernel.img&lt;/code&gt; 开始运行。&lt;/p&gt;
&lt;h3 id=&#34;内核初始化&#34;&gt;内核初始化&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;start_kernel()
&lt;ul&gt;
&lt;li&gt;INIT_TASK(init_task)&lt;/li&gt;
&lt;li&gt;trap_init()&lt;/li&gt;
&lt;li&gt;mm_init()&lt;/li&gt;
&lt;li&gt;sched_init()&lt;/li&gt;
&lt;li&gt;rest_init()
&lt;ul&gt;
&lt;li&gt;kernel_thread(kernel_init, NULL,CLONE_FS)&lt;/li&gt;
&lt;li&gt;kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;内核的启动从入口函数&lt;code&gt;start_kernel()&lt;/code&gt; 开始。在 &lt;code&gt;init/main.c&lt;/code&gt; 文件中，&lt;code&gt;start_kernel&lt;/code&gt; 相当于内核的 &lt;code&gt;main&lt;/code&gt; 函数。打开这个函数，我们会发现，里面是各种各样初始化函数 &lt;code&gt;XXXX_init&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在操作系统里面，先要有个&lt;strong&gt;创始进程&lt;/strong&gt;，有一行指令 &lt;code&gt;set_task_stack_end_magic(&amp;amp;init_task)&lt;/code&gt;。这里面有一个参数 &lt;code&gt;init_task&lt;/code&gt;，它的定义是 &lt;code&gt;struct task_struct init_task = INIT_TASK(init_task)&lt;/code&gt;。它是系统创建的第一个进程，我们称为&lt;code&gt;0&lt;/code&gt;号进程。这是唯一一个没有通过&lt;code&gt;fork&lt;/code&gt; 或者&lt;code&gt;kernel_thread&lt;/code&gt; 产生的进程，是进程列表的第一个。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;trap_init()&lt;/code&gt;里设置了很多**中断门 (Interrupt Gate)**处理各种中断。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mm_init()&lt;/code&gt;初始化内存管理模块，&lt;code&gt;sched_init()&lt;/code&gt;初始化调度模块。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vfs_caches_init()&lt;/code&gt; 会用来初始化基于内存的文件系统 &lt;code&gt;rootfs&lt;/code&gt;。在这个函数里面，会调用 &lt;code&gt;mnt_init()-&amp;gt;init_rootfs()&lt;/code&gt;。这里面有一行代码，&lt;code&gt;register_filesystem(&amp;amp;rootfs_fs_type)&lt;/code&gt;。在 VFS 虚拟文件系统里面注册了一种类型，我们定义为 &lt;code&gt;struct file_system_type rootfs_fs_type&lt;/code&gt;。为了兼容各种各样的文件系统，我们需要将文件的相关数据结构和操作抽象出来，形成一个抽象层对上提供统一的接口，这个抽象层就是 &lt;code&gt;VFS（Virtual File System）&lt;/code&gt;，虚拟文件系统。&lt;/p&gt;
&lt;p&gt;最后&lt;code&gt;start_kernel()&lt;/code&gt;调用&lt;code&gt;rest_init()&lt;/code&gt;来做其他方面的初始化，如初始化 1 号进程，内核态与用户态转化等。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rest_init&lt;/code&gt; 的第一大工作是，用 &lt;code&gt;kernel_thread(kernel_init, NULL, CLONE_FS)&lt;/code&gt;创建第二个进程，这个是&lt;strong&gt;1 号进程&lt;/strong&gt;。这对操作系统意义非凡，因为他将运行第一个用户进程，一旦有了用户进程，运行模式也将发生改变，之前所有资源都是给一个进程用，现在有了用户进程，就会出现抢夺资源的现象。资源也分核心和非核心资源，具有不同权限的进程可以获取不同的资源。&lt;code&gt;x86&lt;/code&gt;提供了分层的权限机制，分成四个&lt;code&gt;Ring&lt;/code&gt;，越往里权限越高。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210727192141.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210727192141.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;操作系统很好地利用了这个机制，将能够访问关键资源的代码放在 &lt;code&gt;Ring0&lt;/code&gt;，我们称为&lt;strong&gt;内核态&lt;/strong&gt;（Kernel Mode）；将普通的程序代码放在 &lt;code&gt;Ring3&lt;/code&gt;，我们称为&lt;strong&gt;用户态&lt;/strong&gt;（User Mode）。&lt;/p&gt;
&lt;p&gt;继续探究&lt;code&gt;kernel_thread()&lt;/code&gt;这个函数，它的一个参数有一个函数&lt;code&gt;kernel_init&lt;/code&gt;，在这个函数里会调用&lt;code&gt;kernel_init_freeable()&lt;/code&gt;，里面有这样一段代码&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ramdisk_execute_command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ramdisk_execute_command&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;/init&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;先不管&lt;code&gt;ramdisk&lt;/code&gt; 是啥，我们回到 &lt;code&gt;kernel_init&lt;/code&gt; 里面。这里面有这样的代码块：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ramdisk_execute_command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;run_init_process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ramdisk_execute_command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;....&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;....&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;try_to_run_init_process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/sbin/init&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;try_to_run_init_process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/etc/init&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;try_to_run_init_process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/bin/init&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;try_to_run_init_process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;/bin/sh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以发现，1 号进程运行的是一个文件，如果我们打开&lt;code&gt;run_init_process&lt;/code&gt;函数，会发现它调用的是&lt;code&gt;do_execve&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;前面讲系统调用的时候，&lt;code&gt;execve&lt;/code&gt; 是一个系统调用，它的作用是运行一个执行文件。加一个 &lt;code&gt;do_&lt;/code&gt; 的往往是内核系统调用的实现。没错，这就是一个系统调用，它会尝试运行 &lt;code&gt;ramdisk&lt;/code&gt; 的“&lt;code&gt;/init”&lt;/code&gt;，或者普通文件系统上的&lt;code&gt;“/sbin/init”“/etc/init”“/bin/init”“/bin/sh”&lt;/code&gt;。不同版本的 Linux 会选择不同的文件启动，但是只要有一个起来了就可以。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;run_init_process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;argv_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;init_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;do_execve&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;getname_kernel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init_filename&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;envp_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如何利用执行 &lt;code&gt;init&lt;/code&gt; 文件的机会，从内核态回到用户态呢？&lt;/p&gt;
&lt;p&gt;我们从系统调用的过程可以得到启发，“用户态 - 系统调用 - 保存寄存器 - 内核态执行系统调用 - 恢复寄存器 - 返回用户态”，然后接着运行。而咱们刚才运行&lt;code&gt;init&lt;/code&gt;，是调用 &lt;code&gt;do_execve&lt;/code&gt;，正是上面的过程的后半部分，从内核态执行系统调用开始。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;do_execve-&amp;gt;do_execveat_common-&amp;gt;exec_binprm-&amp;gt;search_binary_handler&lt;/code&gt;，这里面会调用这段内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;search_binary_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux_binprm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bprm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux_binfmt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;retval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;load_binary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bprm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也就是说，我要运行一个程序，需要加载这个二进制文件，这就是我们常说的项目执行计划书。它是有一定格式的。Linux 下一个常用的格式是 ELF（Executable and Linkable Format，可执行与可链接格式）。于是我们就有了下面这个定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux_binfmt&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;elf_format&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;THIS_MODULE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;load_binary&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_elf_binary&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;load_shlib&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_elf_library&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;core_dump&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;elf_core_dump&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;min_coredump&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ELF_EXEC_PAGESIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这其实就是先调用 &lt;code&gt;load_elf_binary&lt;/code&gt;，最后调用 &lt;code&gt;start_thread&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;start_thread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pt_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_ip&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_sp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;set_user_gs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fs&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ds&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__USER_DS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;es&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__USER_DS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ss&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__USER_DS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cs&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__USER_CS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ip&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_ip&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sp&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_sp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;X86_EFLAGS_IF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;force_iret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;EXPORT_SYMBOL_GPL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_thread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;struct pt_regs&lt;/code&gt;，看名字里的 &lt;code&gt;register&lt;/code&gt;，就是寄存器啊！这个结构就是在系统调用的时候，内核中保存用户态运行上下文的，里面将用户态的代码段 &lt;code&gt;CS&lt;/code&gt;设置为 &lt;code&gt;__USER_CS&lt;/code&gt;，将用户态的数据段 &lt;code&gt;DS&lt;/code&gt; 设置为 &lt;code&gt;__USER_DS&lt;/code&gt;，以及&lt;code&gt;指令指针寄存器 IP&lt;/code&gt;、&lt;code&gt;栈指针寄存器 SP&lt;/code&gt;。这里相当于补上了原来系统调用里，保存寄存器的一个步骤。&lt;/p&gt;
&lt;p&gt;最后的 &lt;code&gt;iret&lt;/code&gt; 是干什么的呢？它是用于从系统调用中返回。这个时候会恢复寄存器。从哪里恢复呢？按说是从进入系统调用的时候，保存的寄存器里面拿出。好在上面的函数补上了寄存器。&lt;code&gt;CS&lt;/code&gt; 和指令指针寄存器 &lt;code&gt;IP&lt;/code&gt; 恢复了，指向用户态下一个要执行的语句。&lt;code&gt;DS&lt;/code&gt; 和函数栈指针 &lt;code&gt;SP&lt;/code&gt; 也被恢复了，指向用户态函数栈的栈顶。所以，下一条指令，就从用户态开始运行了。&lt;/p&gt;
&lt;p&gt;init 终于从内核到用户态了。一开始到用户态的是 ramdisk 的 init，后来会启动真正根文件系统上的 init，成为所有用户态进程的祖先。&lt;/p&gt;
&lt;p&gt;为什么会有 ramdisk 这个东西呢？还记得上一节咱们内核启动的时候，配置过这个参数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;initrd16 /boot/initramfs-3.10.0-862.el7.x86_64.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就是这个东西，这是一个基于内存的文件系统。为啥会有这个呢？&lt;/p&gt;
&lt;p&gt;是因为刚才那个 init 程序是在文件系统上的，文件系统一定是在一个存储设备上的，例如硬盘。Linux 访问存储设备，要有驱动才能访问。如果存储系统数目很有限，那驱动可以直接放到内核里面，反正前面我们加载过内核到内存里了，现在可以直接对存储系统进行访问。&lt;/p&gt;
&lt;p&gt;但是存储系统越来越多了，如果所有市面上的存储系统的驱动都默认放进内核，内核就太大了。这该怎么办呢？&lt;/p&gt;
&lt;p&gt;我们只好先弄一个基于内存的文件系统。内存访问是不需要驱动的，这个就是 &lt;code&gt;ramdisk&lt;/code&gt;。这个时候，&lt;code&gt;ramdisk&lt;/code&gt; 是根文件系统。&lt;/p&gt;
&lt;p&gt;然后，我们开始运行 &lt;code&gt;ramdisk&lt;/code&gt; 上的 &lt;code&gt;/init&lt;/code&gt;。等它运行完了就已经在用户态了。&lt;code&gt;/init&lt;/code&gt; 这个程序会先根据存储系统的类型加载驱动，有了驱动就可以设置真正的根文件系统了。有了真正的根文件系统，&lt;code&gt;ramdisk&lt;/code&gt;上的 &lt;code&gt;/init&lt;/code&gt; 会启动文件系统上的 &lt;code&gt;init&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;接下来就是各种系统的初始化。启动系统的服务，启动控制台，用户就可以登录进来了。&lt;/p&gt;
&lt;p&gt;至此，用户态进程有了一个祖宗，那内核态的进程呢？这就是&lt;code&gt;rest_init&lt;/code&gt;接下来要做的是，&lt;strong&gt;创建 2 号线程&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES)&lt;/code&gt;又一次使用 &lt;code&gt;kernel_thread&lt;/code&gt; 函数创建进程。这里的函数 &lt;code&gt;kthreadd&lt;/code&gt;，负责所有内核态的线程的调度和管理，是内核态所有线程运行的祖先。&lt;/p&gt;
&lt;h3 id=&#34;系统调用&#34;&gt;系统调用&lt;/h3&gt;
&lt;p&gt;Linux 提供了&lt;code&gt;glibc&lt;/code&gt;这个库封装了系统调用，方便用户使用。那么在打开一个文件时，&lt;code&gt;glibc&lt;/code&gt;是如何调用内核的&lt;code&gt;open&lt;/code&gt;的呢？&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;glibc&lt;/code&gt; 的源代码中，有个文件&lt;code&gt;syscalls.list&lt;/code&gt;，里面列着所有 &lt;code&gt;glibc&lt;/code&gt; 的函数对应的系统调用，就像下面这个样子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# File name Caller  Syscall name    Args    Strong name Weak names
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;open    -  open    Ci:siv  __libc_open __open open
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另外，&lt;code&gt;glibc&lt;/code&gt; 还有一个脚本 &lt;code&gt;make-syscall.sh&lt;/code&gt;，可以根据上面的配置文件，对于每一个封装好的系统调用，生成一个文件。这个文件里面定义了一些宏，例如 &lt;code&gt;#define SYSCALL_NAME open&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;glibc&lt;/code&gt; 还有一个文件 &lt;code&gt;syscall-template.S&lt;/code&gt;，使用上面这个宏，定义了这个系统调用的调用方式。&lt;/p&gt;
&lt;p&gt;对于任何一个系统调用，会调用&lt;code&gt;DO_CALL&lt;/code&gt;。这也是一个宏，这个宏 32 位和 64 位的定义是不一样的。&lt;/p&gt;
&lt;h4 id=&#34;32-位系统调用过程&#34;&gt;32 位系统调用过程&lt;/h4&gt;
&lt;p&gt;i386 目录下的&lt;code&gt;sysdep.h&lt;/code&gt; 文件&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/* Linux takes system call arguments in registers:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  syscall number  %eax       call-clobbered
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  arg 1    %ebx       call-saved
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  arg 2    %ecx       call-clobbered
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  arg 3    %edx       call-clobbered
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  arg 4    %esi       call-saved
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  arg 5    %edi       call-saved
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  arg 6    %ebp       call-saved
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;*/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#define DO_CALL(syscall_name, args)                           
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    PUSHARGS_##args                             
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    DOARGS_##args                                
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    movl $SYS_ify (syscall_name), %eax;                          
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ENTER_KERNEL                                 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    POPARGS_##args
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里，我们将请求参数放在寄存器里面，根据系统调用的名称，得到系统调用号，放在寄存器 &lt;code&gt;eax&lt;/code&gt; 里面，然后执行 &lt;code&gt;ENTER_KERNEL&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# define ENTER_KERNEL int $0x80
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ENTER_KERNEL&lt;/code&gt;就是一个软中断，通过它可以陷入 (trap) 内核。&lt;/p&gt;
&lt;p&gt;在内核启动的时候，还记得有一个 &lt;code&gt;trap_init()&lt;/code&gt;，这是一个软中断的陷入门。当接到一个系统调用时，&lt;code&gt;trap_init()&lt;/code&gt;就会调用&lt;code&gt;entry_INT80_32&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;push&lt;/code&gt; 和 &lt;code&gt;SAVE_ALL&lt;/code&gt; 将当前用户态的寄存器，保存在 &lt;code&gt;pt_regs&lt;/code&gt; 结构里面，然后调用 &lt;code&gt;do_syscall_32_irqs_on&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809163844.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809163844.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h4 id=&#34;64-位系统调用过程&#34;&gt;64 位系统调用过程&lt;/h4&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809170711.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809170711.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809171554.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809171554.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="系统初始化">系统初始化</h2>
<h3 id="x86-架构概述">x86 架构概述</h3>
<p><strong>CPU（Central Processing Unit）</strong>：中央处理器，计算机所有设备都围绕它展开工作。</p>
<ul>
<li>运算单元：只管算，例如做加法、做位移等等。但是，它不知道应该算哪些数据，运算结果应该放在哪里。</li>
<li>数据单元：运算单元计算的数据如果每次都要经过总线，到内存里面现拿，这样就太慢了，所以就有了数据单元。数据单元包括 CPU 内部的缓存和寄存器组，空间很小，但是速度飞快，可以暂时存放数据和运算结果。</li>
<li>控制单元：有了放数据的地方，也有了算的地方，还需要有个指挥到底做什么运算的地方，这就是控制单元。控制单元是一个统一的指挥中心，它可以获得下一条指令，然后执行这条指令。这个指令会指导运算单元取出数据单元中的某几个数据，计算出个结果，然后放在数据单元的某个地方。</li>
</ul>
<p><strong>内存（Memory）</strong>：CPU 本身不能保存大量数据，许多复杂的计算需要将中间结果保存下来就必须用到内存。</p>
<p><strong>总线（Bus）</strong>：CPU 和其他设备连接，就靠总线，其实就是主板上密密麻麻的集成电路，这些东西组成了 CPU 和其他设备的高速通道。</p>
<ul>
<li>地址总线：传输地址数据（我想拿内存中哪个位置的数据）</li>
<li>数据总线：传输真正的数据</li>
</ul>
<p>总线就像 CPU 和内存之间的高速公路，总线多少位就类似高速公路多少个车道，但两种总线的位数意义不同。</p>
<p>地址总线的位数决定了访问地址范围有多广，数据总线位数决定了一次能拿多少数据进来。那么 CPU 中总线的位数有没有标准呢？如果没有标准，那操作系统作为软件就很难办了，因为软件层没办法实现通用的运算逻辑。早期每家公司的 CPU 架构都不同，后来历史将 x86 平台推到了<strong>开放，统一，兼容</strong>的位置。</p>
<h4 id="8086-架构图">8086 架构图</h4>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721092854.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721092854.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p><strong>数据单元：</strong> 8086 处理器内部共有 8 个 16 位的通用寄存器，分别是 数据寄存器（AX、BX、CX、DX）、指针寄存器（SP、BP）、变址寄存器（SI、DI）。其中 AX、BX、CX、DX 可以分成两个 8 位的寄存器来使用，分别是 AH、AL、BH、BL、CH、CL、DH、DL，其中 H 就是 High（高位），L 就是 Low（低位）的意思。</p>
<p><strong>控制单元：</strong> IP 寄存器（Instruction Pointer Register）就是指令指针寄存器，它指向代码段中下一条指令的位置。CPU 会根据它来不断地将指令从内存的代码段中，加载到 CPU 的指令队列中，然后交给运算单元去执行。</p>
<p>如果需要切换进程呢？每个进程都分代码段和数据段，为了指向不同进程的地址空间，有四个 16 位的段寄存器，分别是 CS、DS、SS、ES。</p>
<p>其中，<strong>CS</strong> 就是代码段寄存器（Code Segment Register），通过它可以找到代码在内存中的位置；<strong>DS</strong> 是数据段的寄存器（Data Segment Register），通过它可以找到数据在内存中的位置。<strong>SS</strong> 是栈寄存器（Stack Register）。栈是程序运行中一个特殊的数据结构，数据的存取只能从一端进行，秉承后进先出的原则。<strong>ES</strong>是扩展段寄存器（Extra Segment Register）顾名思义。</p>
<p>如果 CPU 运算中需要加载内存中的数据，需要通过 DS 找到内存中的数据，加载到通用寄存器中，应该如何加载呢？对于一个段，有一个起始的地址，而段内的具体位置，我们称为<strong>偏移量（Offset）</strong>。在 CS 和 DS 中都存放着一个段的起始地址。<strong>代码段的偏移量在 IP 寄存器中</strong>，<strong>数据段的偏移量会放在通用寄存器中</strong>。因为段寄存器都是 16 位的，而地址总线是 20 位的，所以通过 *<em>起始地址 <em>16+ 偏移量</em></em> 的方式，将寻址位数都变成 20 位，也就是将 CS 和 DS 的值左移 4 位。</p>
<p>对于只有 20 位地址总线的 8086 来说，寻址空间最大也就是$2^{20}=1\text{M}$，超过这个位置就访问不到了，一个段因为偏移量只有 16 位，所以一个段最大是$2^{16}=64\text{k}$。</p>
<h4 id="32-位处理器">32 位处理器</h4>
<p>随着计算机发展，内存越来越大，总线也越来越宽。在 32 位处理器中，有 32 根地址总线，可以访问 $2^{32}=4\text{G}$ 的内存。使用原来的模式肯定不行了，但是又不能完全抛弃原来的模式，因为这个架构是<strong>开放的</strong>。那么在开发架构的基础上如何保持兼容呢？</p>
<p>首先，通用寄存器有扩展，可以将 8 个 16 位的扩展到 8 个 32 位的，但是依然可以保留 16 位的和 8 位的使用方式。其中，指向下一条指令的指令指针寄存器 IP，就会扩展成 32 位的，同样也兼容 16 位的。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721103205.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721103205.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>段寄存器改动较大，新的段寄存器都改成了 32 位的，每个寄存器又分为<strong>段描述符缓存器（Segment Descriptor）</strong>，和<strong>段选择子寄存器（Selector）</strong> ,现在的段寄存器不在是段的起始地址，段的起始地址保存在表格一样的段描述符缓冲器中，段选择子寄存器保存地址在段描述符缓存器中的哪一项。这样，将一个从段寄存器直接拿到的段起始地址，就变成了<strong>先间接地从段寄存器找到表格中的一项，再从表格中的一项中拿到段起始地址。</strong></p>
<p>虽然现在的这种模式和之前的模式不兼容，但是后面这种模式灵活的非常高，可以保持一直兼容下去。在 32 位的系统架构下，将前一种模式称为<strong>实模式（Real Pattern）</strong>，后一种模式称为<strong>保护模式（Protected Pattern）</strong> 。当系统刚刚启动的时候，CPU 是处于实模式的，这个时候和原来的模式是兼容的。也就是说，哪怕你买了 32 位的 CPU，也支持在原来的模式下运行。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721104550.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721104550.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<blockquote>
<p>汇编命令学习
mov,
call, jmp, int, ret, add, or, xor, shl, shr, push, pop, inc, dec, sub, cmp。</p>
</blockquote>
<h3 id="bios-与-bootloader">BIOS 与 BootLoader</h3>
<p>BIOS：基本输入输出系统</p>
<p>ROM：只读存储器</p>
<p>RAM：随机存取存储器</p>
<p>在我们按下电脑电源键的那一刻，主板就加电了，CPU 就要开始执行指令了，但是刚开始操作系统都没，CPU 执行什么指令呢？这就有了<code>BIOS</code>，它相当于一个指导手册，告诉 CPU 接下来要干啥。</p>
<p>刚开机时，系统初始化代码从 ROM 读取，将 <code>CS</code> 设置为 <code>0xFFFF</code>，将 <code>IP</code> 设置为 <code>0x0000</code>，所以第一条指令就会指向 <code>0xFFFF0</code>，初始化完成后确定访问指令位置。</p>
<p>接下来 BIOS 会检查各个硬件是否正常，检测内容显卡等关键部件的存在于工作状态，设备初始化，执行系统 BIOS 进行系统检测，更新 CMOS 中的扩展系统配置数据 ESCD。这期间也会建立中断向量表和中断服务程序，因为要使用键盘鼠标都需要中断进行。</p>
<p>下一步 BIOS 就得要找操作系统了，操作系统一般安装在硬盘上，但是 BIOS 得先找到启动盘，启动盘一般安装在第一个扇区，占 512 字节，会包含启动的相关代码。在 Linux 中，可以通过<code>Grub2</code>配置这些代码。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">grub2-mkconfig -o /boot/grub2/grub.cfg
</span></span></code></pre></div><p><code>grub2</code>第一个要安装的就是<code>boot.img</code>。它由 <code>boot.S</code>编译而成，一共 <code>512</code> 字节，正式安装到启动盘的第一个扇区。这个扇区通常称为<code>MBR</code>（Master Boot Record，主引导记录 / 扇区）。</p>
<p><code>BIOS</code> 完成任务后，会将 <code>boot.img</code> 从硬盘加载到内存中的 <code>0x7c00</code>来运行。</p>
<p>由于 <code>512</code> 个字节实在有限，<code>boot.img</code> 做不了太多的事情。它能做的最重要的一个事情就是加载<code>grub2</code> 的另一个镜像 <code>core.img</code>。</p>
<p><code>core.img</code> 由<code>lzma_decompress.img</code>、<code>diskboot.img</code>、<code>kernel.img</code> 和一系列的模块组成，功能比较丰富，能做很多事情。</p>
<p><code>boot.img</code> 先加载的是 <code>core.img</code> 的第一个扇区。如果从硬盘启动的话，这个扇区里面是<code>diskboot.img</code>，对应的代码是 <code>diskboot.S</code>。</p>
<p><code>boot.img</code> 将控制权交给 <code>diskboot.img</code> 后，<code>diskboot.img</code> 的任务就是将<code>core.img</code> 的其他部分加载进来，先是解压缩程序 <code>lzma_decompress.img</code>，再往下是 <code>kernel.img</code>，最后是各个模块<code>module</code>对应的映像。这里需要注意，它不是 Linux 的内核，而是<code>grub</code> 的内核。</p>
<p>在这之前，我们所有遇到过的程序都非常非常小，完全可以在实模式下运行，但是随着我们加载的东西越来越大，实模式这<code>1M</code> 的地址空间实在放不下了，所以在真正的解压缩之前，<code>lzma_decompress.img</code> 做了一个重要的决定，就是调用 <code>real_to_prot</code>，切换到<strong>保护模式</strong>，这样就能在更大的寻址空间里面，加载更多的东西。</p>
<p><code>BIOS</code>将加载程序从硬盘的引导扇区加载到指定位置，再跳转到指定位置，将控制权转交给加载程序。加载程序将操作系统代码读取到内存，并将控制权转到操作系统。</p>
<blockquote>
<p>Q：BIOS-操作系统，中间经过加载程序。为何不直接读取？
A：磁盘文件系统多种多样，硬盘出厂时不能限制只能用一种文件系统，而 BIOS 也不能加上识别所有文件系统的代码。所有为了灵活性只读取磁盘的一块，由加载程序来识别磁盘的文件系统。</p>
</blockquote>
<p>切换到保护模式后，将会做以下这些事，大多数都与内存访问方式有关。</p>
<p>首先<strong>启动分段</strong>，就是在内存里面<strong>建立段描述符表</strong>，将寄存器里面的段寄存器变成段选择子，指向某个段描述符，这样就能实现不同进程的切换了。</p>
<p>接着是<strong>启动分页</strong>。能够管理的内存变大了，就需要将内存分成相等大小的块。</p>
<p><strong>打开 Gate20</strong>，也就是第 21 根地址线的控制线。因为在实模式 8086 下，一共就 20 根地址线，最大访问<code>1M</code>的地址空间。切换保护模式的函数<code>DATA32 call real_to_prot</code>会打开<code>Gate A20</code>。</p>
<p>现在好了，有的是空间了。接下来我们要对压缩过的 <strong>kernel.img 进行解压缩</strong>，然后跳转到 <code>kernel.img</code> 开始运行。</p>
<h3 id="内核初始化">内核初始化</h3>
<ul>
<li>start_kernel()
<ul>
<li>INIT_TASK(init_task)</li>
<li>trap_init()</li>
<li>mm_init()</li>
<li>sched_init()</li>
<li>rest_init()
<ul>
<li>kernel_thread(kernel_init, NULL,CLONE_FS)</li>
<li>kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES)</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>内核的启动从入口函数<code>start_kernel()</code> 开始。在 <code>init/main.c</code> 文件中，<code>start_kernel</code> 相当于内核的 <code>main</code> 函数。打开这个函数，我们会发现，里面是各种各样初始化函数 <code>XXXX_init</code>。</p>
<p>在操作系统里面，先要有个<strong>创始进程</strong>，有一行指令 <code>set_task_stack_end_magic(&amp;init_task)</code>。这里面有一个参数 <code>init_task</code>，它的定义是 <code>struct task_struct init_task = INIT_TASK(init_task)</code>。它是系统创建的第一个进程，我们称为<code>0</code>号进程。这是唯一一个没有通过<code>fork</code> 或者<code>kernel_thread</code> 产生的进程，是进程列表的第一个。</p>
<p><code>trap_init()</code>里设置了很多**中断门 (Interrupt Gate)**处理各种中断。</p>
<p><code>mm_init()</code>初始化内存管理模块，<code>sched_init()</code>初始化调度模块。</p>
<p><code>vfs_caches_init()</code> 会用来初始化基于内存的文件系统 <code>rootfs</code>。在这个函数里面，会调用 <code>mnt_init()-&gt;init_rootfs()</code>。这里面有一行代码，<code>register_filesystem(&amp;rootfs_fs_type)</code>。在 VFS 虚拟文件系统里面注册了一种类型，我们定义为 <code>struct file_system_type rootfs_fs_type</code>。为了兼容各种各样的文件系统，我们需要将文件的相关数据结构和操作抽象出来，形成一个抽象层对上提供统一的接口，这个抽象层就是 <code>VFS（Virtual File System）</code>，虚拟文件系统。</p>
<p>最后<code>start_kernel()</code>调用<code>rest_init()</code>来做其他方面的初始化，如初始化 1 号进程，内核态与用户态转化等。</p>
<p><code>rest_init</code> 的第一大工作是，用 <code>kernel_thread(kernel_init, NULL, CLONE_FS)</code>创建第二个进程，这个是<strong>1 号进程</strong>。这对操作系统意义非凡，因为他将运行第一个用户进程，一旦有了用户进程，运行模式也将发生改变，之前所有资源都是给一个进程用，现在有了用户进程，就会出现抢夺资源的现象。资源也分核心和非核心资源，具有不同权限的进程可以获取不同的资源。<code>x86</code>提供了分层的权限机制，分成四个<code>Ring</code>，越往里权限越高。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210727192141.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210727192141.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>操作系统很好地利用了这个机制，将能够访问关键资源的代码放在 <code>Ring0</code>，我们称为<strong>内核态</strong>（Kernel Mode）；将普通的程序代码放在 <code>Ring3</code>，我们称为<strong>用户态</strong>（User Mode）。</p>
<p>继续探究<code>kernel_thread()</code>这个函数，它的一个参数有一个函数<code>kernel_init</code>，在这个函数里会调用<code>kernel_init_freeable()</code>，里面有这样一段代码</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ramdisk_execute_command</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">ramdisk_execute_command</span> <span class="o">=</span> <span class="s">&#34;/init&#34;</span><span class="p">;</span>
</span></span></code></pre></div><p>先不管<code>ramdisk</code> 是啥，我们回到 <code>kernel_init</code> 里面。这里面有这样的代码块：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">ramdisk_execute_command</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">ret</span> <span class="o">=</span> <span class="nf">run_init_process</span><span class="p">(</span><span class="n">ramdisk_execute_command</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">....</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">....</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">try_to_run_init_process</span><span class="p">(</span><span class="s">&#34;/sbin/init&#34;</span><span class="p">)</span> <span class="o">||</span>
</span></span><span class="line"><span class="cl">    <span class="o">!</span><span class="nf">try_to_run_init_process</span><span class="p">(</span><span class="s">&#34;/etc/init&#34;</span><span class="p">)</span> <span class="o">||</span>
</span></span><span class="line"><span class="cl">    <span class="o">!</span><span class="nf">try_to_run_init_process</span><span class="p">(</span><span class="s">&#34;/bin/init&#34;</span><span class="p">)</span> <span class="o">||</span>
</span></span><span class="line"><span class="cl">    <span class="o">!</span><span class="nf">try_to_run_init_process</span><span class="p">(</span><span class="s">&#34;/bin/sh&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span></code></pre></div><p>我们可以发现，1 号进程运行的是一个文件，如果我们打开<code>run_init_process</code>函数，会发现它调用的是<code>do_execve</code>。</p>
<p>前面讲系统调用的时候，<code>execve</code> 是一个系统调用，它的作用是运行一个执行文件。加一个 <code>do_</code> 的往往是内核系统调用的实现。没错，这就是一个系统调用，它会尝试运行 <code>ramdisk</code> 的“<code>/init”</code>，或者普通文件系统上的<code>“/sbin/init”“/etc/init”“/bin/init”“/bin/sh”</code>。不同版本的 Linux 会选择不同的文件启动，但是只要有一个起来了就可以。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">run_init_process</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">init_filename</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">argv_init</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">init_filename</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nf">do_execve</span><span class="p">(</span><span class="nf">getname_kernel</span><span class="p">(</span><span class="n">init_filename</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="k">const</span> <span class="n">__user</span> <span class="o">*</span><span class="p">)</span><span class="n">argv_init</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="k">const</span> <span class="n">__user</span> <span class="o">*</span><span class="p">)</span><span class="n">envp_init</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>如何利用执行 <code>init</code> 文件的机会，从内核态回到用户态呢？</p>
<p>我们从系统调用的过程可以得到启发，“用户态 - 系统调用 - 保存寄存器 - 内核态执行系统调用 - 恢复寄存器 - 返回用户态”，然后接着运行。而咱们刚才运行<code>init</code>，是调用 <code>do_execve</code>，正是上面的过程的后半部分，从内核态执行系统调用开始。</p>
<p><code>do_execve-&gt;do_execveat_common-&gt;exec_binprm-&gt;search_binary_handler</code>，这里面会调用这段内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">search_binary_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">linux_binprm</span> <span class="o">*</span><span class="n">bprm</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="p">......</span>
</span></span><span class="line"><span class="cl">  <span class="k">struct</span> <span class="n">linux_binfmt</span> <span class="o">*</span><span class="n">fmt</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="p">......</span>
</span></span><span class="line"><span class="cl">  <span class="n">retval</span> <span class="o">=</span> <span class="n">fmt</span><span class="o">-&gt;</span><span class="nf">load_binary</span><span class="p">(</span><span class="n">bprm</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="p">......</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>也就是说，我要运行一个程序，需要加载这个二进制文件，这就是我们常说的项目执行计划书。它是有一定格式的。Linux 下一个常用的格式是 ELF（Executable and Linkable Format，可执行与可链接格式）。于是我们就有了下面这个定义：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="k">struct</span> <span class="n">linux_binfmt</span> <span class="n">elf_format</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">module</span>  <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">load_binary</span>  <span class="o">=</span> <span class="n">load_elf_binary</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">load_shlib</span>  <span class="o">=</span> <span class="n">load_elf_library</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">core_dump</span>  <span class="o">=</span> <span class="n">elf_core_dump</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">.</span><span class="n">min_coredump</span>  <span class="o">=</span> <span class="n">ELF_EXEC_PAGESIZE</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>这其实就是先调用 <code>load_elf_binary</code>，最后调用 <code>start_thread</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span>
</span></span><span class="line"><span class="cl"><span class="nf">start_thread</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">new_ip</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">new_sp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="nf">set_user_gs</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">regs</span><span class="o">-&gt;</span><span class="n">fs</span>  <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">regs</span><span class="o">-&gt;</span><span class="n">ds</span>  <span class="o">=</span> <span class="n">__USER_DS</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">regs</span><span class="o">-&gt;</span><span class="n">es</span>  <span class="o">=</span> <span class="n">__USER_DS</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">regs</span><span class="o">-&gt;</span><span class="n">ss</span>  <span class="o">=</span> <span class="n">__USER_DS</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">regs</span><span class="o">-&gt;</span><span class="n">cs</span>  <span class="o">=</span> <span class="n">__USER_CS</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">regs</span><span class="o">-&gt;</span><span class="n">ip</span>  <span class="o">=</span> <span class="n">new_ip</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">regs</span><span class="o">-&gt;</span><span class="n">sp</span>  <span class="o">=</span> <span class="n">new_sp</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">regs</span><span class="o">-&gt;</span><span class="n">flags</span>  <span class="o">=</span> <span class="n">X86_EFLAGS_IF</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="nf">force_iret</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nf">EXPORT_SYMBOL_GPL</span><span class="p">(</span><span class="n">start_thread</span><span class="p">);</span>
</span></span></code></pre></div><p><code>struct pt_regs</code>，看名字里的 <code>register</code>，就是寄存器啊！这个结构就是在系统调用的时候，内核中保存用户态运行上下文的，里面将用户态的代码段 <code>CS</code>设置为 <code>__USER_CS</code>，将用户态的数据段 <code>DS</code> 设置为 <code>__USER_DS</code>，以及<code>指令指针寄存器 IP</code>、<code>栈指针寄存器 SP</code>。这里相当于补上了原来系统调用里，保存寄存器的一个步骤。</p>
<p>最后的 <code>iret</code> 是干什么的呢？它是用于从系统调用中返回。这个时候会恢复寄存器。从哪里恢复呢？按说是从进入系统调用的时候，保存的寄存器里面拿出。好在上面的函数补上了寄存器。<code>CS</code> 和指令指针寄存器 <code>IP</code> 恢复了，指向用户态下一个要执行的语句。<code>DS</code> 和函数栈指针 <code>SP</code> 也被恢复了，指向用户态函数栈的栈顶。所以，下一条指令，就从用户态开始运行了。</p>
<p>init 终于从内核到用户态了。一开始到用户态的是 ramdisk 的 init，后来会启动真正根文件系统上的 init，成为所有用户态进程的祖先。</p>
<p>为什么会有 ramdisk 这个东西呢？还记得上一节咱们内核启动的时候，配置过这个参数：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">initrd16 /boot/initramfs-3.10.0-862.el7.x86_64.img
</span></span></code></pre></div><p>就是这个东西，这是一个基于内存的文件系统。为啥会有这个呢？</p>
<p>是因为刚才那个 init 程序是在文件系统上的，文件系统一定是在一个存储设备上的，例如硬盘。Linux 访问存储设备，要有驱动才能访问。如果存储系统数目很有限，那驱动可以直接放到内核里面，反正前面我们加载过内核到内存里了，现在可以直接对存储系统进行访问。</p>
<p>但是存储系统越来越多了，如果所有市面上的存储系统的驱动都默认放进内核，内核就太大了。这该怎么办呢？</p>
<p>我们只好先弄一个基于内存的文件系统。内存访问是不需要驱动的，这个就是 <code>ramdisk</code>。这个时候，<code>ramdisk</code> 是根文件系统。</p>
<p>然后，我们开始运行 <code>ramdisk</code> 上的 <code>/init</code>。等它运行完了就已经在用户态了。<code>/init</code> 这个程序会先根据存储系统的类型加载驱动，有了驱动就可以设置真正的根文件系统了。有了真正的根文件系统，<code>ramdisk</code>上的 <code>/init</code> 会启动文件系统上的 <code>init</code>。</p>
<p>接下来就是各种系统的初始化。启动系统的服务，启动控制台，用户就可以登录进来了。</p>
<p>至此，用户态进程有了一个祖宗，那内核态的进程呢？这就是<code>rest_init</code>接下来要做的是，<strong>创建 2 号线程</strong>。</p>
<p><code>kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES)</code>又一次使用 <code>kernel_thread</code> 函数创建进程。这里的函数 <code>kthreadd</code>，负责所有内核态的线程的调度和管理，是内核态所有线程运行的祖先。</p>
<h3 id="系统调用">系统调用</h3>
<p>Linux 提供了<code>glibc</code>这个库封装了系统调用，方便用户使用。那么在打开一个文件时，<code>glibc</code>是如何调用内核的<code>open</code>的呢？</p>
<p>在 <code>glibc</code> 的源代码中，有个文件<code>syscalls.list</code>，里面列着所有 <code>glibc</code> 的函数对应的系统调用，就像下面这个样子：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># File name Caller  Syscall name    Args    Strong name Weak names
</span></span><span class="line"><span class="cl">open    -  open    Ci:siv  __libc_open __open open
</span></span></code></pre></div><p>另外，<code>glibc</code> 还有一个脚本 <code>make-syscall.sh</code>，可以根据上面的配置文件，对于每一个封装好的系统调用，生成一个文件。这个文件里面定义了一些宏，例如 <code>#define SYSCALL_NAME open</code>。</p>
<p><code>glibc</code> 还有一个文件 <code>syscall-template.S</code>，使用上面这个宏，定义了这个系统调用的调用方式。</p>
<p>对于任何一个系统调用，会调用<code>DO_CALL</code>。这也是一个宏，这个宏 32 位和 64 位的定义是不一样的。</p>
<h4 id="32-位系统调用过程">32 位系统调用过程</h4>
<p>i386 目录下的<code>sysdep.h</code> 文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">/* Linux takes system call arguments in registers:
</span></span><span class="line"><span class="cl">  syscall number  %eax       call-clobbered
</span></span><span class="line"><span class="cl">  arg 1    %ebx       call-saved
</span></span><span class="line"><span class="cl">  arg 2    %ecx       call-clobbered
</span></span><span class="line"><span class="cl">  arg 3    %edx       call-clobbered
</span></span><span class="line"><span class="cl">  arg 4    %esi       call-saved
</span></span><span class="line"><span class="cl">  arg 5    %edi       call-saved
</span></span><span class="line"><span class="cl">  arg 6    %ebp       call-saved
</span></span><span class="line"><span class="cl">......
</span></span><span class="line"><span class="cl">*/
</span></span><span class="line"><span class="cl">#define DO_CALL(syscall_name, args)                           
</span></span><span class="line"><span class="cl">    PUSHARGS_##args                             
</span></span><span class="line"><span class="cl">    DOARGS_##args                                
</span></span><span class="line"><span class="cl">    movl $SYS_ify (syscall_name), %eax;                          
</span></span><span class="line"><span class="cl">    ENTER_KERNEL                                 
</span></span><span class="line"><span class="cl">    POPARGS_##args
</span></span></code></pre></div><p>这里，我们将请求参数放在寄存器里面，根据系统调用的名称，得到系统调用号，放在寄存器 <code>eax</code> 里面，然后执行 <code>ENTER_KERNEL</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># define ENTER_KERNEL int $0x80
</span></span></code></pre></div><p><code>ENTER_KERNEL</code>就是一个软中断，通过它可以陷入 (trap) 内核。</p>
<p>在内核启动的时候，还记得有一个 <code>trap_init()</code>，这是一个软中断的陷入门。当接到一个系统调用时，<code>trap_init()</code>就会调用<code>entry_INT80_32</code>。</p>
<p>通过 <code>push</code> 和 <code>SAVE_ALL</code> 将当前用户态的寄存器，保存在 <code>pt_regs</code> 结构里面，然后调用 <code>do_syscall_32_irqs_on</code>。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809163844.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809163844.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h4 id="64-位系统调用过程">64 位系统调用过程</h4>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809170711.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809170711.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809171554.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210809171554.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>VSCode 调试 RISC-V 程序</title>
      <link>https://lifeislife.cn/posts/vscode%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/</link>
      <pubDate>Mon, 23 Aug 2021 15:51:51 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/vscode%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/</guid>
      <description>&lt;h2 id=&#34;前提&#34;&gt;前提&lt;/h2&gt;
&lt;p&gt;本文主要涉及 VSCode 的相关配置，编译及调试工具需要提前安装好。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;已经安装好&lt;code&gt;riscv-toolchain&lt;/code&gt;，包括&lt;code&gt;riscv64-unknown-elf-gcc&lt;/code&gt;，&lt;code&gt;riscv64-unknown-elf-gdb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;已经安装好&lt;code&gt;qemu&lt;/code&gt;，包括&lt;code&gt;riscv32-softmmu,riscv32-linux-user,riscv64-softmmu,riscv64-linux-user&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;已经安装好&lt;code&gt;g++&lt;/code&gt;,&lt;code&gt;gdb&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;调试流程简介&#34;&gt;调试流程简介&lt;/h2&gt;
&lt;p&gt;对于我这样的新手，要调试一个项目源码最怕的就是开始，也就是怎么能把项目跑起来。&lt;/p&gt;
&lt;p&gt;我们以一个简单的&lt;code&gt;test&lt;/code&gt;项目，看看在 VSCode 里怎么跑起来。&lt;/p&gt;
&lt;p&gt;拿到源码后，将其以文件夹形式，加入到 VSCode 中，&lt;code&gt;文件 - 打开文件夹 - 选择 test 项目文件夹&lt;/code&gt;。项目就会在 VSCode 中打开，但是此时我们还无法编译运行，我们需要在 VSCode 上
构建出一个 C 语言的编译与调试环境。&lt;/p&gt;
&lt;p&gt;首先得安装一个插件&lt;code&gt;C/C++&lt;/code&gt;，打开插件中心&lt;code&gt;Ctrl+Shit+X&lt;/code&gt;，搜索，安装。&lt;/p&gt;
&lt;p&gt;然后输入&lt;code&gt;F5&lt;/code&gt;，会弹出对话框，选择&lt;code&gt;C++(GDB)&lt;/code&gt;，继续选择&lt;code&gt;g++&lt;/code&gt;。VSCode 会自动创建&lt;code&gt;.vscode&lt;/code&gt;文件夹，已经两个文件&lt;code&gt;launch.json&lt;/code&gt;和&lt;code&gt;tasks.json&lt;/code&gt;。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823193157.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823193157.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;launch.json&lt;/code&gt;用来配置调试环境，&lt;code&gt;tasks.json&lt;/code&gt;主要用来配置编译环境，当然也可以配置其他任务。&lt;code&gt;task.json&lt;/code&gt;里配置的每个任务其实就相当于多开一个控制台。&lt;/p&gt;
&lt;h2 id=&#34;配置tasksjson&#34;&gt;配置&lt;code&gt;tasks.json&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;因为我们先要编译源码，生成&lt;code&gt;.out&lt;/code&gt;或者&lt;code&gt;.exe&lt;/code&gt;文件，才能调试，所以先进行编译任务配置。&lt;/p&gt;
&lt;p&gt;自动生成的文件是个配置模板，我们可以根据自己的实际情况进行配置，也有一部分可以保持默认。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;// tasks.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    // https://code.visualstudio.com/docs/editor/tasks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;2.0.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;tasks&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             // 任务的名字，注意是大小写区分的
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             //会在launch中调用这个名字
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;label&amp;#34;: &amp;#34;C/C++: g++ build active file&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             // 任务执行的是shell
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             // 命令是g++
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;command&amp;#34;: &amp;#34;g++&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             //g++ 后面带的参数
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;&amp;#39;-Wall&amp;#39;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-g&amp;#34;,           // 生成调试信息，否则无法进入断点
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;&amp;#39;-std=c++17&amp;#39;&amp;#34;,     //使用c++17标准编译
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;&amp;#39;${file}&amp;#39;&amp;#34;,        //当前文件名
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-o&amp;#34;,               //对象名，不进行编译优化
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;&amp;#39;${fileBasenameNoExtension}.exe&amp;#39;&amp;#34;,  //当前文件名（去掉扩展名）
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果项目是通过 Makefile 编译的，那就更加简单，只需要配置一个任务即可。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;version&amp;#34;: &amp;#34;2.0.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;tasks&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       //任务的名字方便执行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;label&amp;#34;: &amp;#34;Make Project&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;command&amp;#34;: &amp;#34;make&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;args&amp;#34;:[
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          //8线程编译
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &amp;#34;-j8&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行该任务时就会执行&lt;code&gt;make&lt;/code&gt;命令进行编译。&lt;/p&gt;
&lt;h2 id=&#34;配置launchjson&#34;&gt;配置&lt;code&gt;launch.json&lt;/code&gt;&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;// launch.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;0.2.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;configurations&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            //调试任务的名字
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;name&amp;#34;: &amp;#34;g++ - Build and debug active file&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            //在launch之前运行的任务名，这个名字一定要跟tasks.json中的任务名字大小写一致
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;preLaunchTask&amp;#34;: &amp;#34;C/C++: g++ build active file&amp;#34;,  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;cppdbg&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;request&amp;#34;: &amp;#34;launch&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            //需要运行的是当前打开文件的目录中，
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            //名字和当前文件相同，但扩展名为exe的程序
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;program&amp;#34;: &amp;#34;${fileDirname}/${fileBasenameNoExtension}.exe&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 选为true则会在打开控制台后停滞，暂时不执行程序
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;stopAtEntry&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 当前工作路径：当前文件所在的工作空间
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;cwd&amp;#34;: &amp;#34;${workspaceFolder}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;environment&amp;#34;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 是否使用外部控制台
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;externalConsole&amp;#34;: false,  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;MIMode&amp;#34;: &amp;#34;gdb&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;setupCommands&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;description&amp;#34;: &amp;#34;Enable pretty-printing for gdb&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;text&amp;#34;: &amp;#34;-enable-pretty-printing&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;ignoreFailures&amp;#34;: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;运行&#34;&gt;运行&lt;/h2&gt;
&lt;p&gt;经过以上配置后，我们打开&lt;code&gt;main.cpp&lt;/code&gt;文件，在&lt;code&gt;cout&lt;/code&gt;处打一个断点，按&lt;code&gt;F5&lt;/code&gt;，即可编译，运行，调试。一定要打开&lt;code&gt;main.cpp&lt;/code&gt;文件，不能随便打开文件就开始哦。因为我们在配置时使用了一些预定义，比如&lt;code&gt;${file}&lt;/code&gt;表示当前文件，所以只有打开需要调试的文件才能开始。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823201621.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823201621.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;程序将会在&lt;code&gt;cout&lt;/code&gt;语句停下来。&lt;/p&gt;
&lt;p&gt;我们可以注意一下界面下方的控制台，可以更直观了解&lt;code&gt;launch.jason&lt;/code&gt;和&lt;code&gt;tasks.jason&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823202012.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823202012.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;右边的框，就是我们在&lt;code&gt;tasks.jason&lt;/code&gt;中配置的任务，左边的框就是我们在&lt;code&gt;tasks.jason&lt;/code&gt;中&lt;code&gt;command&lt;/code&gt;以及&lt;code&gt;args&lt;/code&gt;的内容，他就是帮我们提前写好编译的选项。然后在 shell 中运行。&lt;/p&gt;
&lt;h2 id=&#34;编译调试-risc-v-程序&#34;&gt;编译调试 RISC-V 程序&lt;/h2&gt;
&lt;p&gt;了解以上这些，就可以按需配置所需的环境了。我们还是从&lt;code&gt;tasks.jason&lt;/code&gt;开始。因为开发用的电脑是&lt;code&gt;x86&lt;/code&gt;的，所以先要编译出&lt;code&gt;riscv&lt;/code&gt;的程序，再用模拟器模拟出&lt;code&gt;rsicv&lt;/code&gt;的环境，然后在模拟的环境中运行程序，最后才能开始调试。&lt;/p&gt;
&lt;p&gt;假设已经安装好开头所提到的工具。首先配置&lt;code&gt;tasks.jason&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;2.0.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;tasks&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 编译当前代码
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;label&amp;#34;: &amp;#34;C/C++(RISCV): Build active file&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 编译器的位置
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;command&amp;#34;: &amp;#34;/opt/riscv/bin/riscv64-unknown-elf-g++&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-Wall&amp;#34;, // 开启所有警告
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-g&amp;#34;, // 生成调试信息s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;${file}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-o&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&amp;#34; // 我选择将可执行文件放在debug目录下
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 当前工作路径：执行当前命令时所在的路径
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;options&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;cwd&amp;#34;: &amp;#34;${workspaceFolder}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;problemMatcher&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;$gcc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 启动qemu供调试器连接
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;label&amp;#34;: &amp;#34;Run Qemu Server(RISCV)&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;dependsOn&amp;#34;: &amp;#34;C/C++(RISCV): Build active file&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;command&amp;#34;: &amp;#34;qemu-system-riscv64&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-g&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;65500&amp;#34;, // gdb端口，自己定义
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 有时候qemu有可能没法退出，故编写一个任务用于强行结束qemu进程
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;label&amp;#34;: &amp;#34;Kill Qemu Server(RISCV)&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;command&amp;#34;: &amp;#34;ps -C qemu-riscv64 --no-headers | cut -d \\  -f 1 | xargs kill -9&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tasks.jason&lt;/code&gt;是可以配置多个任务的，第一个任务用来编译成&lt;code&gt;riscv&lt;/code&gt;架构下的程序，第二个任务用来启动 qemu，让程序在 qemu 上运行起来。&lt;/p&gt;
&lt;p&gt;第一个任务中，&lt;code&gt;command&lt;/code&gt;就是配置编译器&lt;code&gt;riscv64-unkonown-elf-gcc&lt;/code&gt;的属性，第二个任务中，&lt;code&gt;command&lt;/code&gt;是配置 qemu 模拟器&lt;code&gt;qemu-system-riscv32&lt;/code&gt;的属性。第三个任务中，用来配置结束 qemu 模拟器的命令。&lt;/p&gt;
&lt;p&gt;接下来配置&lt;code&gt;launch.jason&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;0.2.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;configurations&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        { 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;name&amp;#34;: &amp;#34;C/C++(RISCV) - Debug Active File&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;cppdbg&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;request&amp;#34;: &amp;#34;launch&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;program&amp;#34;: &amp;#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;stopAtEntry&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;cwd&amp;#34;: &amp;#34;${workspaceFolder}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;environment&amp;#34;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;externalConsole&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;MIMode&amp;#34;: &amp;#34;gdb&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;setupCommands&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;description&amp;#34;: &amp;#34;为 gdb 启用整齐打印&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;text&amp;#34;: &amp;#34;-enable-pretty-printing&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;ignoreFailures&amp;#34;: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // RISC-V工具链中的gdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;miDebuggerPath&amp;#34;: &amp;#34;/opt/riscv/bin/riscv64-unknown-elf-gdb&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 这里需要与task.json中定义的端口一致
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;miDebuggerServerAddress&amp;#34;: &amp;#34;localhost:65500&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们在配置&lt;code&gt;x86&lt;/code&gt;下的调试环境时，&lt;code&gt;launch.jason&lt;/code&gt;中有个&lt;code&gt;&amp;quot;preLaunchTask&amp;quot;: &amp;quot;C/C++: g++ build active file&amp;quot;&lt;/code&gt;，属性，这个属性的目的是在启动调试之前，先执行任务名字为&lt;code&gt;&amp;quot;C/C++: g++ build active file&amp;quot;&lt;/code&gt;任务，也是就编译的任务。&lt;/p&gt;
&lt;p&gt;因为启动 qemu 会导致阻塞，所以这里没有加&lt;code&gt;preLaunchTask&lt;/code&gt;，在启动调试之前，先把 qemu 运行起来。输入&lt;code&gt;Ctrl+Shift+P&lt;/code&gt;，打开 VSCode 命令行。输入&lt;code&gt;Run Task&lt;/code&gt;，&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094556.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094556.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;点击第一个，选择任务，我们可以看到出现的三个任务就是我们在&lt;code&gt;tasks.jason&lt;/code&gt;中配置的三个任务。选择第一个 Build，编译出程序，再重复操作，选择第三个执行 QEMU 任务。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094609.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094609.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;预定义变量&#34;&gt;预定义变量&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://code.visualstudio.com/docs/editor/variables-reference#_predefined-variables&#34;&gt;官网&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="前提">前提</h2>
<p>本文主要涉及 VSCode 的相关配置，编译及调试工具需要提前安装好。</p>
<ul>
<li>已经安装好<code>riscv-toolchain</code>，包括<code>riscv64-unknown-elf-gcc</code>，<code>riscv64-unknown-elf-gdb</code></li>
<li>已经安装好<code>qemu</code>，包括<code>riscv32-softmmu,riscv32-linux-user,riscv64-softmmu,riscv64-linux-user</code></li>
<li>已经安装好<code>g++</code>,<code>gdb</code></li>
</ul>
<h2 id="调试流程简介">调试流程简介</h2>
<p>对于我这样的新手，要调试一个项目源码最怕的就是开始，也就是怎么能把项目跑起来。</p>
<p>我们以一个简单的<code>test</code>项目，看看在 VSCode 里怎么跑起来。</p>
<p>拿到源码后，将其以文件夹形式，加入到 VSCode 中，<code>文件 - 打开文件夹 - 选择 test 项目文件夹</code>。项目就会在 VSCode 中打开，但是此时我们还无法编译运行，我们需要在 VSCode 上
构建出一个 C 语言的编译与调试环境。</p>
<p>首先得安装一个插件<code>C/C++</code>，打开插件中心<code>Ctrl+Shit+X</code>，搜索，安装。</p>
<p>然后输入<code>F5</code>，会弹出对话框，选择<code>C++(GDB)</code>，继续选择<code>g++</code>。VSCode 会自动创建<code>.vscode</code>文件夹，已经两个文件<code>launch.json</code>和<code>tasks.json</code>。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823193157.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823193157.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p><code>launch.json</code>用来配置调试环境，<code>tasks.json</code>主要用来配置编译环境，当然也可以配置其他任务。<code>task.json</code>里配置的每个任务其实就相当于多开一个控制台。</p>
<h2 id="配置tasksjson">配置<code>tasks.json</code></h2>
<p>因为我们先要编译源码，生成<code>.out</code>或者<code>.exe</code>文件，才能调试，所以先进行编译任务配置。</p>
<p>自动生成的文件是个配置模板，我们可以根据自己的实际情况进行配置，也有一部分可以保持默认。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">// tasks.json
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    // https://code.visualstudio.com/docs/editor/tasks
</span></span><span class="line"><span class="cl">    &#34;version&#34;: &#34;2.0.0&#34;,
</span></span><span class="line"><span class="cl">    &#34;tasks&#34;: [
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">             // 任务的名字，注意是大小写区分的
</span></span><span class="line"><span class="cl">             //会在launch中调用这个名字
</span></span><span class="line"><span class="cl">            &#34;label&#34;: &#34;C/C++: g++ build active file&#34;, 
</span></span><span class="line"><span class="cl">             // 任务执行的是shell
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;shell&#34;, 
</span></span><span class="line"><span class="cl">             // 命令是g++
</span></span><span class="line"><span class="cl">            &#34;command&#34;: &#34;g++&#34;, 
</span></span><span class="line"><span class="cl">             //g++ 后面带的参数
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [
</span></span><span class="line"><span class="cl">                &#34;&#39;-Wall&#39;&#34;,
</span></span><span class="line"><span class="cl">                &#34;-g&#34;,           // 生成调试信息，否则无法进入断点
</span></span><span class="line"><span class="cl">                &#34;&#39;-std=c++17&#39;&#34;,     //使用c++17标准编译
</span></span><span class="line"><span class="cl">                &#34;&#39;${file}&#39;&#34;,        //当前文件名
</span></span><span class="line"><span class="cl">                &#34;-o&#34;,               //对象名，不进行编译优化
</span></span><span class="line"><span class="cl">                &#34;&#39;${fileBasenameNoExtension}.exe&#39;&#34;,  //当前文件名（去掉扩展名）
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>如果项目是通过 Makefile 编译的，那就更加简单，只需要配置一个任务即可。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">  &#34;version&#34;: &#34;2.0.0&#34;,
</span></span><span class="line"><span class="cl">  &#34;tasks&#34;: [
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">       //任务的名字方便执行
</span></span><span class="line"><span class="cl">      &#34;label&#34;: &#34;Make Project&#34;,
</span></span><span class="line"><span class="cl">      &#34;type&#34;: &#34;shell&#34;,
</span></span><span class="line"><span class="cl">      &#34;command&#34;: &#34;make&#34;,
</span></span><span class="line"><span class="cl">      &#34;args&#34;:[
</span></span><span class="line"><span class="cl">          //8线程编译
</span></span><span class="line"><span class="cl">          &#34;-j8&#34;,
</span></span><span class="line"><span class="cl">      ],
</span></span><span class="line"><span class="cl">    },
</span></span><span class="line"><span class="cl">  ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>运行该任务时就会执行<code>make</code>命令进行编译。</p>
<h2 id="配置launchjson">配置<code>launch.json</code></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">// launch.json
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    &#34;version&#34;: &#34;0.2.0&#34;,
</span></span><span class="line"><span class="cl">    &#34;configurations&#34;: [
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            //调试任务的名字
</span></span><span class="line"><span class="cl">            &#34;name&#34;: &#34;g++ - Build and debug active file&#34;, 
</span></span><span class="line"><span class="cl">            //在launch之前运行的任务名，这个名字一定要跟tasks.json中的任务名字大小写一致
</span></span><span class="line"><span class="cl">            &#34;preLaunchTask&#34;: &#34;C/C++: g++ build active file&#34;,  
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;cppdbg&#34;,
</span></span><span class="line"><span class="cl">            &#34;request&#34;: &#34;launch&#34;,
</span></span><span class="line"><span class="cl">            //需要运行的是当前打开文件的目录中，
</span></span><span class="line"><span class="cl">            //名字和当前文件相同，但扩展名为exe的程序
</span></span><span class="line"><span class="cl">            &#34;program&#34;: &#34;${fileDirname}/${fileBasenameNoExtension}.exe&#34;, 
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [],
</span></span><span class="line"><span class="cl">            // 选为true则会在打开控制台后停滞，暂时不执行程序
</span></span><span class="line"><span class="cl">            &#34;stopAtEntry&#34;: false,
</span></span><span class="line"><span class="cl">            // 当前工作路径：当前文件所在的工作空间
</span></span><span class="line"><span class="cl">            &#34;cwd&#34;: &#34;${workspaceFolder}&#34;,
</span></span><span class="line"><span class="cl">            &#34;environment&#34;: [],
</span></span><span class="line"><span class="cl">            // 是否使用外部控制台
</span></span><span class="line"><span class="cl">            &#34;externalConsole&#34;: false,  
</span></span><span class="line"><span class="cl">            &#34;MIMode&#34;: &#34;gdb&#34;,
</span></span><span class="line"><span class="cl">            &#34;setupCommands&#34;: [
</span></span><span class="line"><span class="cl">                {
</span></span><span class="line"><span class="cl">                    &#34;description&#34;: &#34;Enable pretty-printing for gdb&#34;,
</span></span><span class="line"><span class="cl">                    &#34;text&#34;: &#34;-enable-pretty-printing&#34;,
</span></span><span class="line"><span class="cl">                    &#34;ignoreFailures&#34;: true
</span></span><span class="line"><span class="cl">                }
</span></span><span class="line"><span class="cl">            ]
</span></span><span class="line"><span class="cl">        }]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><h2 id="运行">运行</h2>
<p>经过以上配置后，我们打开<code>main.cpp</code>文件，在<code>cout</code>处打一个断点，按<code>F5</code>，即可编译，运行，调试。一定要打开<code>main.cpp</code>文件，不能随便打开文件就开始哦。因为我们在配置时使用了一些预定义，比如<code>${file}</code>表示当前文件，所以只有打开需要调试的文件才能开始。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823201621.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823201621.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>程序将会在<code>cout</code>语句停下来。</p>
<p>我们可以注意一下界面下方的控制台，可以更直观了解<code>launch.jason</code>和<code>tasks.jason</code>。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823202012.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823202012.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>右边的框，就是我们在<code>tasks.jason</code>中配置的任务，左边的框就是我们在<code>tasks.jason</code>中<code>command</code>以及<code>args</code>的内容，他就是帮我们提前写好编译的选项。然后在 shell 中运行。</p>
<h2 id="编译调试-risc-v-程序">编译调试 RISC-V 程序</h2>
<p>了解以上这些，就可以按需配置所需的环境了。我们还是从<code>tasks.jason</code>开始。因为开发用的电脑是<code>x86</code>的，所以先要编译出<code>riscv</code>的程序，再用模拟器模拟出<code>rsicv</code>的环境，然后在模拟的环境中运行程序，最后才能开始调试。</p>
<p>假设已经安装好开头所提到的工具。首先配置<code>tasks.jason</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    &#34;version&#34;: &#34;2.0.0&#34;,
</span></span><span class="line"><span class="cl">    &#34;tasks&#34;: [
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            // 编译当前代码
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;shell&#34;,
</span></span><span class="line"><span class="cl">            &#34;label&#34;: &#34;C/C++(RISCV): Build active file&#34;,
</span></span><span class="line"><span class="cl">            // 编译器的位置
</span></span><span class="line"><span class="cl">            &#34;command&#34;: &#34;/opt/riscv/bin/riscv64-unknown-elf-g++&#34;,
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [
</span></span><span class="line"><span class="cl">                &#34;-Wall&#34;, // 开启所有警告
</span></span><span class="line"><span class="cl">                &#34;-g&#34;, // 生成调试信息s
</span></span><span class="line"><span class="cl">                &#34;${file}&#34;,
</span></span><span class="line"><span class="cl">                &#34;-o&#34;,
</span></span><span class="line"><span class="cl">                &#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&#34; // 我选择将可执行文件放在debug目录下
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">            // 当前工作路径：执行当前命令时所在的路径
</span></span><span class="line"><span class="cl">            &#34;options&#34;: {
</span></span><span class="line"><span class="cl">                &#34;cwd&#34;: &#34;${workspaceFolder}&#34;
</span></span><span class="line"><span class="cl">            },
</span></span><span class="line"><span class="cl">            &#34;problemMatcher&#34;: [
</span></span><span class="line"><span class="cl">                &#34;$gcc&#34;
</span></span><span class="line"><span class="cl">            ]
</span></span><span class="line"><span class="cl">        },
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            // 启动qemu供调试器连接
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;shell&#34;,
</span></span><span class="line"><span class="cl">            &#34;label&#34;: &#34;Run Qemu Server(RISCV)&#34;,
</span></span><span class="line"><span class="cl">            &#34;dependsOn&#34;: &#34;C/C++(RISCV): Build active file&#34;,
</span></span><span class="line"><span class="cl">            &#34;command&#34;: &#34;qemu-system-riscv64&#34;,
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [
</span></span><span class="line"><span class="cl">                &#34;-g&#34;,
</span></span><span class="line"><span class="cl">                &#34;65500&#34;, // gdb端口，自己定义
</span></span><span class="line"><span class="cl">                &#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&#34;
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">        },
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            // 有时候qemu有可能没法退出，故编写一个任务用于强行结束qemu进程
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;shell&#34;,
</span></span><span class="line"><span class="cl">            &#34;label&#34;: &#34;Kill Qemu Server(RISCV)&#34;,
</span></span><span class="line"><span class="cl">            &#34;command&#34;: &#34;ps -C qemu-riscv64 --no-headers | cut -d \\  -f 1 | xargs kill -9&#34;,
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p><code>tasks.jason</code>是可以配置多个任务的，第一个任务用来编译成<code>riscv</code>架构下的程序，第二个任务用来启动 qemu，让程序在 qemu 上运行起来。</p>
<p>第一个任务中，<code>command</code>就是配置编译器<code>riscv64-unkonown-elf-gcc</code>的属性，第二个任务中，<code>command</code>是配置 qemu 模拟器<code>qemu-system-riscv32</code>的属性。第三个任务中，用来配置结束 qemu 模拟器的命令。</p>
<p>接下来配置<code>launch.jason</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    &#34;version&#34;: &#34;0.2.0&#34;,
</span></span><span class="line"><span class="cl">    &#34;configurations&#34;: [
</span></span><span class="line"><span class="cl">        { 
</span></span><span class="line"><span class="cl">            &#34;name&#34;: &#34;C/C++(RISCV) - Debug Active File&#34;,
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;cppdbg&#34;,
</span></span><span class="line"><span class="cl">            &#34;request&#34;: &#34;launch&#34;,
</span></span><span class="line"><span class="cl">            &#34;program&#34;: &#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&#34;,
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [],
</span></span><span class="line"><span class="cl">            &#34;stopAtEntry&#34;: false,
</span></span><span class="line"><span class="cl">            &#34;cwd&#34;: &#34;${workspaceFolder}&#34;,
</span></span><span class="line"><span class="cl">            &#34;environment&#34;: [],
</span></span><span class="line"><span class="cl">            &#34;externalConsole&#34;: false,
</span></span><span class="line"><span class="cl">            &#34;MIMode&#34;: &#34;gdb&#34;,
</span></span><span class="line"><span class="cl">            &#34;setupCommands&#34;: [
</span></span><span class="line"><span class="cl">                {
</span></span><span class="line"><span class="cl">                    &#34;description&#34;: &#34;为 gdb 启用整齐打印&#34;,
</span></span><span class="line"><span class="cl">                    &#34;text&#34;: &#34;-enable-pretty-printing&#34;,
</span></span><span class="line"><span class="cl">                    &#34;ignoreFailures&#34;: true
</span></span><span class="line"><span class="cl">                }
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">            // RISC-V工具链中的gdb
</span></span><span class="line"><span class="cl">            &#34;miDebuggerPath&#34;: &#34;/opt/riscv/bin/riscv64-unknown-elf-gdb&#34;, 
</span></span><span class="line"><span class="cl">            // 这里需要与task.json中定义的端口一致
</span></span><span class="line"><span class="cl">            &#34;miDebuggerServerAddress&#34;: &#34;localhost:65500&#34; 
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>我们在配置<code>x86</code>下的调试环境时，<code>launch.jason</code>中有个<code>&quot;preLaunchTask&quot;: &quot;C/C++: g++ build active file&quot;</code>，属性，这个属性的目的是在启动调试之前，先执行任务名字为<code>&quot;C/C++: g++ build active file&quot;</code>任务，也是就编译的任务。</p>
<p>因为启动 qemu 会导致阻塞，所以这里没有加<code>preLaunchTask</code>，在启动调试之前，先把 qemu 运行起来。输入<code>Ctrl+Shift+P</code>，打开 VSCode 命令行。输入<code>Run Task</code>，</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094556.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094556.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>点击第一个，选择任务，我们可以看到出现的三个任务就是我们在<code>tasks.jason</code>中配置的三个任务。选择第一个 Build，编译出程序，再重复操作，选择第三个执行 QEMU 任务。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094609.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094609.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="预定义变量">预定义变量</h2>
<p><a href="https://code.visualstudio.com/docs/editor/variables-reference#_predefined-variables">官网</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>进程间通信（IPC）之信号量（Semaphore）</title>
      <link>https://lifeislife.cn/posts/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1ipc%E4%B9%8B%E4%BF%A1%E5%8F%B7%E9%87%8Fsemaphore/</link>
      <pubDate>Thu, 19 Aug 2021 15:36:02 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1ipc%E4%B9%8B%E4%BF%A1%E5%8F%B7%E9%87%8Fsemaphore/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;
&lt;p&gt;为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题，我们需要一种方法，它可以通过生成并使用令牌来授权，在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制，让一个临界区同一时间只有一个线程在访问它，也就是说信号量是用来调协进程对共享资源的访问的。&lt;/p&gt;
&lt;p&gt;信号量是一个特殊的变量，程序对其访问都是原子操作，且只允许对它进行等待（即&lt;code&gt;P&lt;/code&gt;) 和发送（即&lt;code&gt;V&lt;/code&gt;) 信息操作。最简单的信号量是只能取 0 和 1 的变量，这也是信号量最常见的一种形式，叫做二进制信号量。而可以取多个正整数的信号量被称为通用信号量。这里主要讨论二进制信号量。&lt;/p&gt;
&lt;p&gt;由于信号量只能进行两种操作等待和发送信号，即 P(sv) 和 V(sv),他们的行为是这样的：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;P(sv)&lt;/code&gt;：如果&lt;code&gt;sv&lt;/code&gt;的值大于零，就给它减 1；如果它的值为零，就挂起该进程的执行&lt;/p&gt;
&lt;p&gt;&lt;code&gt;V(sv)&lt;/code&gt;：如果有其他进程因等待&lt;code&gt;sv&lt;/code&gt;而被挂起，就让它恢复运行，如果没有进程因等待&lt;code&gt;sv&lt;/code&gt;而挂起，就给它加 1.&lt;/p&gt;
&lt;p&gt;举个例子，就是两个进程共享信号量&lt;code&gt;sv&lt;/code&gt;，一旦其中一个进程执行了&lt;code&gt;P(sv)&lt;/code&gt;操作，它将得到信号量，并可以进入临界区，使&lt;code&gt;sv&lt;/code&gt;减 1。而第二个进程将被阻止进入临界区，因为当它试图执行&lt;code&gt;P(sv)&lt;/code&gt;时，&lt;code&gt;sv&lt;/code&gt;为 0，它会被挂起以等待第一个进程离开临界区域并执行&lt;code&gt;V(sv)&lt;/code&gt;释放信号量，这时第二个进程就可以恢复执行。&lt;/p&gt;
&lt;p&gt;本文&lt;a href=&#34;https://github.com/Dunky-Z/learning-linux/blob/main/IPC/Semaphore/main.c&#34;&gt;代码同步在这里&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;相关函数&#34;&gt;相关函数&lt;/h2&gt;
&lt;p&gt;Linux 提供了一组精心设计的信号量接口来对信号进行操作，它们不只是针对二进制信号量，下面将会对这些函数进行介绍，但请注意，这些函数都是用来对成组的信号量值进行操作的。它们声明在头文件 sys/sem.h 中。&lt;/p&gt;
&lt;h3 id=&#34;semget&#34;&gt;&lt;code&gt;semget()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;它的作用是创建一个新信号量或取得一个已有信号量，原型为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;semget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_sems&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;key&lt;/code&gt;是整数值（唯一非零），不相关的进程可以通过它访问一个信号量，它代表程序可能要使用的某个资源，程序对所有信号量的访问都是间接的，程序先通过调用&lt;code&gt;semget()&lt;/code&gt;函数并提供一个键，再由系统生成一个相应的信号标识符（&lt;code&gt;semget()&lt;/code&gt;函数的返回值），只有&lt;code&gt;semget()&lt;/code&gt;函数才直接使用信号量键，所有其他的信号量函数使用由&lt;code&gt;semget()&lt;/code&gt;函数返回的信号量标识符。如果多个程序使用相同的&lt;code&gt;key&lt;/code&gt;值，&lt;code&gt;key&lt;/code&gt;将负责协调工作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;num_sems&lt;/code&gt;指定需要的信号量数目，它的值几乎总是 1。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;sem_flags&lt;/code&gt;是一组标志，当想要当信号量不存在时创建一个新的信号量，可以和值&lt;code&gt;IPC_CREAT&lt;/code&gt;做按位或操作。设置了&lt;code&gt;IPC_CREAT&lt;/code&gt;标志后，即使给出的键是一个已有信号量的键，也不会产生错误。而&lt;code&gt;IPC_CREAT | IPC_EXCL&lt;/code&gt;则可以创建一个新的，唯一的信号量，如果信号量已存在，返回一个错误。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;semget()&lt;/code&gt;函数成功返回一个相应信号标识符（非零），失败返回&lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;semop&#34;&gt;&lt;code&gt;semop()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;它的作用是改变信号量的值，原型为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;semop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sembuf&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sem_opa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_sem_ops&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;sem_id&lt;/code&gt;是由&lt;code&gt;semget()&lt;/code&gt;返回的信号量标识符，&lt;code&gt;sembuf&lt;/code&gt;结构的定义如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sembuf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 除非使用一组信号量，否则它为0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 信号量在一次操作中需要改变的数据，通常是两个数，一个是-1，即 P（等待）操作，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;c1&#34;&gt;// 一个是+1，即V（发送信号）操作。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_flg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 通常为 SEM_UNDO，使操作系统跟踪信号，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;c1&#34;&gt;// 并在进程没有释放该信号量而终止时，操作系统释放信号量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;num_sem_ops&lt;/code&gt;：操作&lt;code&gt;sops&lt;/code&gt;中的操作个数，通常取值为 1&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;semctl&#34;&gt;&lt;code&gt;semctl()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;该函数用来直接控制信号量信息，它的原型为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;semctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果有第四个参数，它通常是一个&lt;code&gt;union semum&lt;/code&gt;结构，定义如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;union&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semun&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semid_ds&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;前两个参数与前面一个函数中的一样，&lt;code&gt;command&lt;/code&gt;通常是下面两个值中的其中一个&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SETVAL&lt;/code&gt;：用来把信号量初始化为一个已知的值。p 这个值通过 union semun 中的 val 成员设置，其作用是在信号量第一次使用前对它进行设置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;IPC_RMID&lt;/code&gt;：用于删除一个已经无需继续使用的信号量标识符。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<h2 id="简介">简介</h2>
<p>为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题，我们需要一种方法，它可以通过生成并使用令牌来授权，在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制，让一个临界区同一时间只有一个线程在访问它，也就是说信号量是用来调协进程对共享资源的访问的。</p>
<p>信号量是一个特殊的变量，程序对其访问都是原子操作，且只允许对它进行等待（即<code>P</code>) 和发送（即<code>V</code>) 信息操作。最简单的信号量是只能取 0 和 1 的变量，这也是信号量最常见的一种形式，叫做二进制信号量。而可以取多个正整数的信号量被称为通用信号量。这里主要讨论二进制信号量。</p>
<p>由于信号量只能进行两种操作等待和发送信号，即 P(sv) 和 V(sv),他们的行为是这样的：</p>
<p><code>P(sv)</code>：如果<code>sv</code>的值大于零，就给它减 1；如果它的值为零，就挂起该进程的执行</p>
<p><code>V(sv)</code>：如果有其他进程因等待<code>sv</code>而被挂起，就让它恢复运行，如果没有进程因等待<code>sv</code>而挂起，就给它加 1.</p>
<p>举个例子，就是两个进程共享信号量<code>sv</code>，一旦其中一个进程执行了<code>P(sv)</code>操作，它将得到信号量，并可以进入临界区，使<code>sv</code>减 1。而第二个进程将被阻止进入临界区，因为当它试图执行<code>P(sv)</code>时，<code>sv</code>为 0，它会被挂起以等待第一个进程离开临界区域并执行<code>V(sv)</code>释放信号量，这时第二个进程就可以恢复执行。</p>
<p>本文<a href="https://github.com/Dunky-Z/learning-linux/blob/main/IPC/Semaphore/main.c">代码同步在这里</a>。</p>
<h2 id="相关函数">相关函数</h2>
<p>Linux 提供了一组精心设计的信号量接口来对信号进行操作，它们不只是针对二进制信号量，下面将会对这些函数进行介绍，但请注意，这些函数都是用来对成组的信号量值进行操作的。它们声明在头文件 sys/sem.h 中。</p>
<h3 id="semget"><code>semget()</code></h3>
<p>它的作用是创建一个新信号量或取得一个已有信号量，原型为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">semget</span><span class="p">(</span><span class="kt">key_t</span> <span class="n">key</span><span class="p">,</span> <span class="kt">int</span> <span class="n">num_sems</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sem_flags</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li>
<p><code>key</code>是整数值（唯一非零），不相关的进程可以通过它访问一个信号量，它代表程序可能要使用的某个资源，程序对所有信号量的访问都是间接的，程序先通过调用<code>semget()</code>函数并提供一个键，再由系统生成一个相应的信号标识符（<code>semget()</code>函数的返回值），只有<code>semget()</code>函数才直接使用信号量键，所有其他的信号量函数使用由<code>semget()</code>函数返回的信号量标识符。如果多个程序使用相同的<code>key</code>值，<code>key</code>将负责协调工作。</p>
</li>
<li>
<p><code>num_sems</code>指定需要的信号量数目，它的值几乎总是 1。</p>
</li>
<li>
<p><code>sem_flags</code>是一组标志，当想要当信号量不存在时创建一个新的信号量，可以和值<code>IPC_CREAT</code>做按位或操作。设置了<code>IPC_CREAT</code>标志后，即使给出的键是一个已有信号量的键，也不会产生错误。而<code>IPC_CREAT | IPC_EXCL</code>则可以创建一个新的，唯一的信号量，如果信号量已存在，返回一个错误。</p>
</li>
</ul>
<p><code>semget()</code>函数成功返回一个相应信号标识符（非零），失败返回<code>-1</code>.</p>
<h3 id="semop"><code>semop()</code></h3>
<p>它的作用是改变信号量的值，原型为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">semop</span><span class="p">(</span><span class="kt">int</span> <span class="n">sem_id</span><span class="p">,</span> <span class="k">struct</span> <span class="n">sembuf</span> <span class="o">*</span><span class="n">sem_opa</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">num_sem_ops</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li>
<p><code>sem_id</code>是由<code>semget()</code>返回的信号量标识符，<code>sembuf</code>结构的定义如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sembuf</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">short</span> <span class="n">sem_num</span><span class="p">;</span> <span class="c1">// 除非使用一组信号量，否则它为0
</span></span></span><span class="line"><span class="cl">    <span class="kt">short</span> <span class="n">sem_op</span><span class="p">;</span>  <span class="c1">// 信号量在一次操作中需要改变的数据，通常是两个数，一个是-1，即 P（等待）操作，
</span></span></span><span class="line"><span class="cl">                <span class="c1">// 一个是+1，即V（发送信号）操作。
</span></span></span><span class="line"><span class="cl">    <span class="kt">short</span> <span class="n">sem_flg</span><span class="p">;</span> <span class="c1">// 通常为 SEM_UNDO，使操作系统跟踪信号，
</span></span></span><span class="line"><span class="cl">                <span class="c1">// 并在进程没有释放该信号量而终止时，操作系统释放信号量
</span></span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
<li>
<p><code>num_sem_ops</code>：操作<code>sops</code>中的操作个数，通常取值为 1</p>
</li>
</ul>
<h3 id="semctl"><code>semctl()</code></h3>
<p>该函数用来直接控制信号量信息，它的原型为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">semctl</span><span class="p">(</span><span class="kt">int</span> <span class="n">sem_id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sem_num</span><span class="p">,</span> <span class="kt">int</span> <span class="n">command</span><span class="p">,</span> <span class="p">...);</span>
</span></span></code></pre></div><ul>
<li>
<p>如果有第四个参数，它通常是一个<code>union semum</code>结构，定义如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">union</span> <span class="n">semun</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">semid_ds</span> <span class="o">*</span><span class="n">buf</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">short</span> <span class="o">*</span><span class="n">arry</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
<li>
<p>前两个参数与前面一个函数中的一样，<code>command</code>通常是下面两个值中的其中一个</p>
</li>
<li>
<p><code>SETVAL</code>：用来把信号量初始化为一个已知的值。p 这个值通过 union semun 中的 val 成员设置，其作用是在信号量第一次使用前对它进行设置。</p>
</li>
<li>
<p><code>IPC_RMID</code>：用于删除一个已经无需继续使用的信号量标识符。</p>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>进程间通信（IPC）之消息队列（MessageQueue）</title>
      <link>https://lifeislife.cn/posts/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1ipc%E4%B9%8B%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97messagequeue/</link>
      <pubDate>Thu, 19 Aug 2021 10:53:09 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1ipc%E4%B9%8B%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97messagequeue/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;
&lt;p&gt;消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。&lt;/p&gt;
&lt;p&gt;每个数据块都被认为含有一个类型，接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样，每个数据块都有一个最大长度的限制。&lt;/p&gt;
&lt;p&gt;本文&lt;a href=&#34;https://github.com/Dunky-Z/learning-linux/tree/main/IPC/MessageQueue&#34;&gt;代码同步在这里&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;相关函数&#34;&gt;相关函数&lt;/h2&gt;
&lt;h3 id=&#34;msgget&#34;&gt;&lt;code&gt;msgget()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;该函数用来创建和访问一个消息队列。它的原型为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;msgget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgflg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;key&lt;/code&gt;：与其他的 IPC 机制一样，程序&lt;strong&gt;必须提供一个键&lt;/strong&gt;来命名某个特定的消息队列。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msgflg&lt;/code&gt;是一个权限标志，表示消息队列的&lt;strong&gt;访问权限&lt;/strong&gt;，它与文件的访问权限一样。&lt;code&gt;msgflg&lt;/code&gt;可以与&lt;code&gt;IPC_CREAT&lt;/code&gt;做或操作，表示当 key 所命名的消息队列不存在时创建一个消息队列，如果 key 所命名的消息队列存在时，&lt;code&gt;IPC_CREAT&lt;/code&gt;标志会被忽略，而只返回一个标识符。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它返回一个以&lt;code&gt;key&lt;/code&gt;命名的消息队列的标识符（非零整数），失败时返回&lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;msgsnd&#34;&gt;&lt;code&gt;msgsnd()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;该函数用来把消息添加到消息队列中。它的原型为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;msgsend&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msg_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg_sz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgflg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;msgid&lt;/code&gt;是由&lt;code&gt;msgget&lt;/code&gt;函数返回的消息队列标识符。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;msg_ptr&lt;/code&gt;是一个指向准备发送消息的指针，但是消息的数据结构却有一定的要求，指针&lt;code&gt;msg_ptr&lt;/code&gt;所指向的消息结构一定要是以一个&lt;strong&gt;长整型成员变量开始的结构体&lt;/strong&gt;，接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_message&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;message_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* The data you wish to transfer */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;msg_sz&lt;/code&gt; 是&lt;code&gt;msg_ptr&lt;/code&gt;指向的消息的长度&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;msgflg&lt;/code&gt; 用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果调用成功，消息数据的副本将被放到消息队列中，并返回&lt;code&gt;0&lt;/code&gt;，失败时返回&lt;code&gt;-1&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;msgrcv&#34;&gt;&lt;code&gt;msgrcv()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;该函数用来从一个消息队列获取消息，它的原型为&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;msgrcv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msg_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg_st&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgtype&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgflg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;前三个参数参照前面的解释&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msgtype&lt;/code&gt; 可以实现一种简单的接收优先级。如果&lt;code&gt;msgtype&lt;/code&gt;为&lt;code&gt;0&lt;/code&gt;，就获取队列中的第一个消息。如果它的值大于零，将获取具有相同消息类型的第一个信息。如果它小于零，就获取类型等于或小于&lt;code&gt;msgtype&lt;/code&gt;的绝对值的第一个消息。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;msgflg&lt;/code&gt; 用于控制当队列中没有相应类型的消息可以接收时将发生的事情。&lt;/li&gt;
&lt;li&gt;调用成功时，该函数返回放到接收缓存区中的字节数，消息被复制到由&lt;code&gt;msg_ptr&lt;/code&gt;指向的用户分配的缓存区中，然后删除消息队列中的对应消息。失败时返回&lt;code&gt;-1&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;msgctl&#34;&gt;&lt;code&gt;msgctl()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;该函数用来控制消息队列，它与共享内存的shmctl函数相似，它的原型为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;msgctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;command&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgid_ds&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;msgid&lt;/code&gt;同上&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;command&lt;/code&gt;是将要采取的动作，它可以取3个值:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IPC_STAT&lt;/code&gt;：把&lt;code&gt;msgid_ds&lt;/code&gt;结构中的数据设置为消息队列的当前关联值，即用消息队列的当前关联值覆盖&lt;code&gt;msgid_ds&lt;/code&gt;的值。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPC_SET&lt;/code&gt;：如果进程有足够的权限，就把消息列队的当前关联值设置为msgid_ds结构中给出的值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPC_RMID&lt;/code&gt;：删除消息队列&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;buf&lt;/code&gt;是指向&lt;code&gt;msgid_ds&lt;/code&gt;结构的指针，它指向消息队列模式和访问权限的结构。&lt;code&gt;msgid_ds&lt;/code&gt;结构至少包括以下成员：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgid_ds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shm_perm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;uid_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shm_perm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;mode_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shm_perm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;成功时返回 0，失败时返回 -1.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//msgsnd
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;errno.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/msg.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MAX_TXT 512
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg_st&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_TXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg_st&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BUFSIZ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgKey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ftok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;./msgsnd.c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;msgget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msgKey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0666&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;IPC_CREAT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;masget failed error: %d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Enter some text: &lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;fgets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BUFSIZ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stdin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msg_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 注意 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;strcpy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 向队列里发送数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;msgsnd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAX_TXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;msgsnd failed&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 输入 end 结束输入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;strncmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;end&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//msgrcv
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;errno.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/msg.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MAX_TXT 512
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg_st&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_TXT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msg_st&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgtype&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgKey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ftok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;./msgsnd.c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;msgget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msgKey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0666&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;IPC_CREAT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;masget failed error: %d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;errno&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;msgrcv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msgid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BUFSIZ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msgtype&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;msgsnd failed&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_FAILURE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;You wrote: %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;strncmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;end&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;EXIT_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;运行结果&#34;&gt;运行结果&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210819142858.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210819142858.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210819142913.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210819142913.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="简介">简介</h2>
<p>消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。</p>
<p>每个数据块都被认为含有一个类型，接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样，每个数据块都有一个最大长度的限制。</p>
<p>本文<a href="https://github.com/Dunky-Z/learning-linux/tree/main/IPC/MessageQueue">代码同步在这里</a>。</p>
<h2 id="相关函数">相关函数</h2>
<h3 id="msgget"><code>msgget()</code></h3>
<p>该函数用来创建和访问一个消息队列。它的原型为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">msgget</span><span class="p">(</span><span class="kt">key_t</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="kt">int</span> <span class="n">msgflg</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li><code>key</code>：与其他的 IPC 机制一样，程序<strong>必须提供一个键</strong>来命名某个特定的消息队列。</li>
<li><code>msgflg</code>是一个权限标志，表示消息队列的<strong>访问权限</strong>，它与文件的访问权限一样。<code>msgflg</code>可以与<code>IPC_CREAT</code>做或操作，表示当 key 所命名的消息队列不存在时创建一个消息队列，如果 key 所命名的消息队列存在时，<code>IPC_CREAT</code>标志会被忽略，而只返回一个标识符。</li>
</ul>
<p>它返回一个以<code>key</code>命名的消息队列的标识符（非零整数），失败时返回<code>-1</code>.</p>
<h3 id="msgsnd"><code>msgsnd()</code></h3>
<p>该函数用来把消息添加到消息队列中。它的原型为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">msgsend</span><span class="p">(</span><span class="kt">int</span> <span class="n">msgid</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">msg_ptr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">msg_sz</span><span class="p">,</span> <span class="kt">int</span> <span class="n">msgflg</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li>
<p><code>msgid</code>是由<code>msgget</code>函数返回的消息队列标识符。</p>
</li>
<li>
<p><code>msg_ptr</code>是一个指向准备发送消息的指针，但是消息的数据结构却有一定的要求，指针<code>msg_ptr</code>所指向的消息结构一定要是以一个<strong>长整型成员变量开始的结构体</strong>，接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">my_message</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">long</span> <span class="kt">int</span> <span class="n">message_type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* The data you wish to transfer */</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
<li>
<p><code>msg_sz</code> 是<code>msg_ptr</code>指向的消息的长度</p>
</li>
<li>
<p><code>msgflg</code> 用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情</p>
</li>
<li>
<p>如果调用成功，消息数据的副本将被放到消息队列中，并返回<code>0</code>，失败时返回<code>-1</code>.</p>
</li>
</ul>
<h3 id="msgrcv"><code>msgrcv()</code></h3>
<p>该函数用来从一个消息队列获取消息，它的原型为</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">msgrcv</span><span class="p">(</span><span class="kt">int</span> <span class="n">msgid</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">msg_ptr</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">msg_st</span><span class="p">,</span> <span class="kt">long</span> <span class="kt">int</span> <span class="n">msgtype</span><span class="p">,</span> <span class="kt">int</span> <span class="n">msgflg</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li>前三个参数参照前面的解释</li>
<li><code>msgtype</code> 可以实现一种简单的接收优先级。如果<code>msgtype</code>为<code>0</code>，就获取队列中的第一个消息。如果它的值大于零，将获取具有相同消息类型的第一个信息。如果它小于零，就获取类型等于或小于<code>msgtype</code>的绝对值的第一个消息。</li>
<li><code>msgflg</code> 用于控制当队列中没有相应类型的消息可以接收时将发生的事情。</li>
<li>调用成功时，该函数返回放到接收缓存区中的字节数，消息被复制到由<code>msg_ptr</code>指向的用户分配的缓存区中，然后删除消息队列中的对应消息。失败时返回<code>-1</code>。</li>
</ul>
<h3 id="msgctl"><code>msgctl()</code></h3>
<p>该函数用来控制消息队列，它与共享内存的shmctl函数相似，它的原型为：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">msgctl</span><span class="p">(</span><span class="kt">int</span> <span class="n">msgid</span><span class="p">,</span> <span class="kt">int</span> <span class="n">command</span><span class="p">,</span> <span class="k">struct</span> <span class="n">msgid_ds</span> <span class="o">*</span><span class="n">buf</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li>
<p><code>msgid</code>同上</p>
</li>
<li>
<p><code>command</code>是将要采取的动作，它可以取3个值:</p>
<ul>
<li><code>IPC_STAT</code>：把<code>msgid_ds</code>结构中的数据设置为消息队列的当前关联值，即用消息队列的当前关联值覆盖<code>msgid_ds</code>的值。</li>
<li><code>IPC_SET</code>：如果进程有足够的权限，就把消息列队的当前关联值设置为msgid_ds结构中给出的值</li>
<li><code>IPC_RMID</code>：删除消息队列</li>
</ul>
</li>
<li>
<p><code>buf</code>是指向<code>msgid_ds</code>结构的指针，它指向消息队列模式和访问权限的结构。<code>msgid_ds</code>结构至少包括以下成员：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">msgid_ds</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uid_t</span> <span class="n">shm_perm</span><span class="p">.</span><span class="n">uid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">uid_t</span> <span class="n">shm_perm</span><span class="p">.</span><span class="n">gid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">mode_t</span> <span class="n">shm_perm</span><span class="p">.</span><span class="n">mode</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
<li>
<p>成功时返回 0，失败时返回 -1.</p>
</li>
</ul>
<h2 id="demo">Demo</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//msgsnd
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;errno.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/msg.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#define MAX_TXT 512
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">msg_st</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">long</span> <span class="kt">int</span> <span class="n">msg_type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="n">msg</span><span class="p">[</span><span class="n">MAX_TXT</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">msg_st</span> <span class="n">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">msgid</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="n">BUFSIZ</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="kt">key_t</span> <span class="n">msgKey</span> <span class="o">=</span> <span class="nf">ftok</span><span class="p">(</span><span class="s">&#34;./msgsnd.c&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">msgid</span> <span class="o">=</span> <span class="nf">msgget</span><span class="p">(</span><span class="n">msgKey</span><span class="p">,</span> <span class="mo">0666</span> <span class="o">|</span> <span class="n">IPC_CREAT</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">msgid</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;masget failed error: %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">errno</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;Enter some text: </span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">fgets</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">BUFSIZ</span><span class="p">,</span> <span class="n">stdin</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">message</span><span class="p">.</span><span class="n">msg_type</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 注意 2
</span></span></span><span class="line"><span class="cl">        <span class="nf">strcpy</span><span class="p">(</span><span class="n">message</span><span class="p">.</span><span class="n">msg</span><span class="p">,</span> <span class="n">buffer</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// 向队列里发送数据
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">msgsnd</span><span class="p">(</span><span class="n">msgid</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">message</span><span class="p">,</span> <span class="n">MAX_TXT</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nf">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;msgsnd failed</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// 输入 end 结束输入
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">strncmp</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="s">&#34;end&#34;</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nf">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//msgrcv
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;errno.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/msg.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#define MAX_TXT 512
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">msg_st</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">long</span> <span class="kt">int</span> <span class="n">msg_type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="n">msg</span><span class="p">[</span><span class="n">MAX_TXT</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">msg_st</span> <span class="n">message</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">msgid</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">long</span> <span class="kt">int</span> <span class="n">msgtype</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">key_t</span> <span class="n">msgKey</span> <span class="o">=</span> <span class="nf">ftok</span><span class="p">(</span><span class="s">&#34;./msgsnd.c&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">msgid</span> <span class="o">=</span> <span class="nf">msgget</span><span class="p">(</span><span class="n">msgKey</span><span class="p">,</span> <span class="mo">0666</span> <span class="o">|</span> <span class="n">IPC_CREAT</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">msgid</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;masget failed error: %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">errno</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">msgrcv</span><span class="p">(</span><span class="n">msgid</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">message</span><span class="p">,</span> <span class="n">BUFSIZ</span><span class="p">,</span> <span class="n">msgtype</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nf">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;msgsnd failed</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;You wrote: %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">message</span><span class="p">.</span><span class="n">msg</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">strncmp</span><span class="p">(</span><span class="n">message</span><span class="p">.</span><span class="n">msg</span><span class="p">,</span> <span class="s">&#34;end&#34;</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="运行结果">运行结果</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210819142858.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210819142858.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210819142913.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210819142913.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux(Ubuntu) 环境下安装 VSCode</title>
      <link>https://lifeislife.cn/posts/linux-ubuntu-%E7%8E%AF%E5%A2%83%E4%B8%8B%E5%AE%89%E8%A3%85vscode/</link>
      <pubDate>Thu, 19 Aug 2021 09:38:22 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux-ubuntu-%E7%8E%AF%E5%A2%83%E4%B8%8B%E5%AE%89%E8%A3%85vscode/</guid>
      <description>&lt;p&gt;本来不想写这一篇的，安装 VSCode 时随便搜一下就 OK 了，但是因为 APT 源中没有 VSCode，所以需要找下载网址，几次的安装经历下来，找下载网址也经历了一番折腾。今天又要安装一遍，就顺手记录一下吧。以后翻自己记录总比翻全网记录方便。&lt;/p&gt;
&lt;h2 id=&#34;官方文档&#34;&gt;官方文档&lt;/h2&gt;
&lt;p&gt;其实最完备安装教程在&lt;a href=&#34;https://code.visualstudio.com/docs/setup/linux&#34;&gt;官方文档&lt;/a&gt;里。本文也算是对官方文档的一个翻译版吧。&lt;/p&gt;
&lt;h2 id=&#34;基于-debian-和-ubuntu-的发行版&#34;&gt;基于 Debian 和 Ubuntu 的发行版&lt;/h2&gt;
&lt;p&gt;如果&lt;a href=&#34;https://go.microsoft.com/fwlink/?LinkID=760868&#34;&gt;下载了.deb 安装包&lt;/a&gt;，那么只需要一个命令就可以完成安装了。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install ./&amp;lt;file&amp;gt;.deb
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;无奈的是，我需要在开发机安装，无法下载安装包，但是我又不想用&lt;code&gt;ftp&lt;/code&gt;传来传去，要是&lt;code&gt;apt&lt;/code&gt;能完成，绝不单独下载安装包。&lt;/p&gt;
&lt;p&gt;可以使用以下脚本手动安装存储库和密钥&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor &amp;gt; packages.microsoft.gpg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo sh -c &amp;#39;echo &amp;#34;deb [arch=amd64,arm64,armhf signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main&amp;#34; &amp;gt; /etc/apt/sources.list.d/vscode.list&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -f packages.microsoft.gpg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更新与安装&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install apt-transport-https
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install code # or code-insiders
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>本来不想写这一篇的，安装 VSCode 时随便搜一下就 OK 了，但是因为 APT 源中没有 VSCode，所以需要找下载网址，几次的安装经历下来，找下载网址也经历了一番折腾。今天又要安装一遍，就顺手记录一下吧。以后翻自己记录总比翻全网记录方便。</p>
<h2 id="官方文档">官方文档</h2>
<p>其实最完备安装教程在<a href="https://code.visualstudio.com/docs/setup/linux">官方文档</a>里。本文也算是对官方文档的一个翻译版吧。</p>
<h2 id="基于-debian-和-ubuntu-的发行版">基于 Debian 和 Ubuntu 的发行版</h2>
<p>如果<a href="https://go.microsoft.com/fwlink/?LinkID=760868">下载了.deb 安装包</a>，那么只需要一个命令就可以完成安装了。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo apt install ./&lt;file&gt;.deb
</span></span></code></pre></div><p>无奈的是，我需要在开发机安装，无法下载安装包，但是我又不想用<code>ftp</code>传来传去，要是<code>apt</code>能完成，绝不单独下载安装包。</p>
<p>可以使用以下脚本手动安装存储库和密钥</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor &gt; packages.microsoft.gpg
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo sh -c &#39;echo &#34;deb [arch=amd64,arm64,armhf signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main&#34; &gt; /etc/apt/sources.list.d/vscode.list&#39;
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">rm -f packages.microsoft.gpg
</span></span></code></pre></div><p>更新与安装</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo apt install apt-transport-https
</span></span><span class="line"><span class="cl">sudo apt update
</span></span><span class="line"><span class="cl">sudo apt install code # or code-insiders
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Linux 操作系统-内存管理</title>
      <link>https://lifeislife.cn/posts/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</link>
      <pubDate>Thu, 19 Aug 2021 09:37:04 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</guid>
      <description>&lt;h2 id=&#34;内存管理概述&#34;&gt;内存管理概述&lt;/h2&gt;
&lt;p&gt;计算机所谓的“计算”指的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;进程和线程对于 CPU 的使用&lt;/li&gt;
&lt;li&gt;对内存的管理&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;独享内存空间的原理&#34;&gt;独享内存空间的原理&lt;/h3&gt;
&lt;p&gt;每个进程都独享一段内存空间，并且真实物理内存地址对进程不可见，操作系统会给进程分配一个虚拟地址，每个进程看到的内存地址都是从 0 开始。操作系统会将不同进程的虚拟地址和不同内存的物理地址做映射。当程序访问虚拟地址时，由内核的数据结构进行转换，转换成不同的物理地址，这样不同的进程运行的时候，写入的是不同的物理地址。&lt;/p&gt;
&lt;h3 id=&#34;规划虚拟地址空间&#34;&gt;规划虚拟地址空间&lt;/h3&gt;
&lt;p&gt;通过以上的原理，我们可以看出，操作系统的内存管理，主要分为三个方面。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;物理内存的管理；&lt;/li&gt;
&lt;li&gt;虚拟地址的管理；&lt;/li&gt;
&lt;li&gt;虚拟地址和物理地址如何映射；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;进程获取了一段独立的虚拟内存空间后，可以不用管其他进程，“任意”使用这片内存，但是也有一点规则。这篇内存需要存放内核态和用户态的内容。高地址存放内核态的内容，低地址存放用户态的内容。具体分界线 64 位与 32 位不同，暂不深究。&lt;/p&gt;
&lt;p&gt;我们从最低位开始排起，先是&lt;strong&gt;Text Segment、Data Segment 和 BSS Segment&lt;/strong&gt;。Text Segment 是存放二进制可执行代码的位置，Data Segment 存放静态常量，BSS Segment 存放未初始化的静态变量。是不是觉得这几个名字很熟悉？没错，咱们前面讲 ELF 格式的时候提到过，在二进制执行文件里面，就有这三个部分。这里就是把二进制执行文件的三个部分加载到内存里面。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129170110.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129170110.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;接下来是&lt;strong&gt;堆&lt;/strong&gt;（Heap）&lt;strong&gt;段&lt;/strong&gt;。堆是往高地址增长的，是用来动态分配内存的区域，&lt;code&gt;malloc&lt;/code&gt; 就是在这里面分配的。
接下来的区域是&lt;strong&gt;Memory Mapping Segment&lt;/strong&gt;。这块地址可以用来把文件映射进内存用的，如果二进制的执行文件依赖于某个动态链接库，就是在这个区域里面将 so 文件映射到了内存中。
再下面就是&lt;strong&gt;栈&lt;/strong&gt;（Stack）&lt;strong&gt;地址段&lt;/strong&gt;。主线程的函数调用的函数栈就是用这里的。&lt;/p&gt;
&lt;p&gt;普通进程不能访问内核空间，如果需要进行更高权限的工作，就需要系统调用进入内核。每一段进程的内存空间存放的内容各不相同，但是进入内核后看到的都是同一个内核空间，同一个进程列表。&lt;/p&gt;
&lt;p&gt;内核的代码访问内核的数据结构，大部分的情况下都是使用虚拟地址的，虽然内核代码权限很大，但是能够使用的虚拟地址范围也只能在内核空间，也即内核代码访问内核数据结构。&lt;/p&gt;
&lt;p&gt;接下来，我们需要知道，如何将其映射成为物理地址呢？&lt;/p&gt;
&lt;p&gt;咱们前面讲 x86 CPU 的时候，讲过分段机制，咱们规划虚拟空间的时候，也是将空间分成多个段进行保存。我们来看看分段机制的原理。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129182908.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129182908.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;分段机制下的虚拟地址由两部分组成，&lt;strong&gt;段选择子&lt;/strong&gt;和&lt;strong&gt;段内偏移量&lt;/strong&gt;。段选择子就保存在咱们前面讲过的段寄存器里面。段选择子里面最重要的是&lt;strong&gt;段号&lt;/strong&gt;，用作段表的索引。段表里面保存的是这个段的&lt;strong&gt;基地址&lt;/strong&gt;、&lt;strong&gt;段的界限&lt;/strong&gt;和&lt;strong&gt;特权等级&lt;/strong&gt;等。虚拟地址中的段内偏移量应该位于 0 和段界限之间。如果段内偏移量是合法的，就将段基地址加上段内偏移量得到物理内存地址。&lt;/p&gt;
&lt;p&gt;例如，我们将上面的虚拟空间分成以下 4 个段，用 0～3 来编号。每个段在段表中有一个项，在物理空间中，段的排列如下图的右边所示。如果要访问段 2 中偏移量 600 的虚拟地址，我们可以计算出物理地址为，段 2 基地址 2000 + 偏移量 600 = 2600。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129183334.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129183334.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;在 Linux 里面，段表全称&lt;strong&gt;段描述符表&lt;/strong&gt;（segment descriptors），放在&lt;strong&gt;全局描述符表 GDT&lt;/strong&gt;（Global Descriptor Table）里面，会有下面的宏来初始化段描述符表里面的表项。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define GDT_ENTRY_INIT(flags, base, limit) { { { \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    .a = ((limit) &amp;amp; 0xffff) | (((base) &amp;amp; 0xffff) &amp;lt;&amp;lt; 16), \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    .b = (((base) &amp;amp; 0xff0000) &amp;gt;&amp;gt; 16) | (((flags) &amp;amp; 0xf0ff) &amp;lt;&amp;lt; 8) | \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;      ((limit) &amp;amp; 0xf0000) | ((base) &amp;amp; 0xff000000), \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;  } } }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个段表项由段基地址 base、段界限 limit，还有一些标识符组成。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;DEFINE_PER_CPU_PAGE_ALIGNED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gdt_page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gdt_page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gdt&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_X86_64
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_KERNEL32_CS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xc09b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_KERNEL_CS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xa09b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_KERNEL_DS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xc093&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_DEFAULT_USER32_CS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xc0fb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_DEFAULT_USER_DS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xc0f3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_DEFAULT_USER_CS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xa0fb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_KERNEL_CS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xc09a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_KERNEL_DS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xc092&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_DEFAULT_USER_CS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xc0fa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GDT_ENTRY_DEFAULT_USER_DS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mh&#34;&gt;0xc0f2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0xfffff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;EXPORT_PER_CPU_SYMBOL_GPL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gdt_page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里面对于 64 位的和 32 位的，都定义了内核代码段、内核数据段、用户代码段和用户数据段。另外，还会定义下面四个段选择子，指向上面的段描述符表项。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define __KERNEL_CS      (GDT_ENTRY_KERNEL_CS*8)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define __KERNEL_DS      (GDT_ENTRY_KERNEL_DS*8)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define __USER_DS      (GDT_ENTRY_DEFAULT_USER_DS*8 + 3)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define __USER_CS      (GDT_ENTRY_DEFAULT_USER_CS*8 + 3)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过分析，我们发现，所有的段的起始地址都是一样的，都是 0。所以，在 Linux 操作系统中，并没有使用到全部的分段功能。那分段是不是完全没有用处呢？分段可以做权限审核，例如用户态 DPL 是 3，内核态 DPL 是 0。当用户态试图访问内核态的时候，会因为权限不足而报错。
其实 Linux 倾向于另外一种从虚拟地址到物理地址的转换方式，称为&lt;strong&gt;分页&lt;/strong&gt;（Paging）。对于物理内存，操作系统把它分成一块一块大小相同的页，这样更方便管理，例如有的内存页面长时间不用了，可以&lt;strong&gt;暂时写到硬盘上&lt;/strong&gt;，称为&lt;strong&gt;换出&lt;/strong&gt;。一旦需要的时候，再&lt;strong&gt;加载进来&lt;/strong&gt;，叫作&lt;strong&gt;换入&lt;/strong&gt;。这样可以扩大可用物理内存的大小，提高物理内存的利用率。&lt;/p&gt;
&lt;p&gt;这个换入和换出都是以页为单位的。页面的大小一般为 4KB。为了能够定位和访问每个页，需要有个页表，保存每个页的起始地址，再加上在页内的偏移量，组成线性地址，就能对于内存中的每个位置进行访问了。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129185728.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129185728.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;虚拟地址分为两部分，&lt;strong&gt;页号&lt;/strong&gt;和&lt;strong&gt;页内偏移&lt;/strong&gt;。页号作为页表的索引，页表包含物理页每页所在物理内存的基地址。这个基地址与页内偏移的组合就形成了物理内存地址。&lt;/p&gt;
&lt;p&gt;32 位环境下，虚拟地址空间共 4GB。如果分成 4KB 一个页，那就是 1M 个页。每个页表项需要 4 个字节来存储，那么整个 4GB 空间的映射就需要 4MB 的内存来存储映射表。如果每个进程都有自己的映射表，100 个进程就需要 400MB 的内存。对于内核来讲，有点大了。&lt;/p&gt;
&lt;p&gt;页表中所有页表项必须提前建好，并且要求是连续的。如果不连续，就没有办法通过虚拟地址里面的页号找到对应的页表项了。&lt;/p&gt;
&lt;p&gt;那怎么办呢？我们可以试着将页表再分页，4G 的空间需要 4M 的页表来存储映射。我们把这 4M 分成 1K（1024）个 4K，每个 4K 又能放在一页里面，这样 1K 个 4K 就是 1K 个页，这 1K 个页也需要一个表进行管理，我们称为页目录表，这个页目录表里面有 1K 项，每项 4 个字节，页目录表大小也是 4K。&lt;/p&gt;
&lt;p&gt;页目录有 1K 项，用 10 位就可以表示访问页目录的哪一项。这一项其实对应的是一整页的页表项，也即 4K 的页表项。每个页表项也是 4 个字节，因而一整页的页表项是 1K 个。再用 10 位就可以表示访问页表项的哪一项，页表项中的一项对应的就是一个页，是存放数据的页，这个页的大小是 4K，用 12 位可以定位这个页内的任何一个位置。&lt;/p&gt;
&lt;p&gt;这样加起来正好 32 位，也就是用前 10 位定位到页目录表中的一项。将这一项对应的页表取出来共 1k 项，再用中间 10 位定位到页表中的一项，将这一项对应的存放数据的页取出来，再用最后 12 位定位到页中的具体位置访问数据。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129192245.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129192245.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;你可能会问，如果这样的话，映射 4GB 地址空间就需要 4MB+4KB 的内存，这样不是更大了吗？当然如果页是满的，当时是更大了，但是，我们往往不会为一个进程分配那么多内存。&lt;/p&gt;
&lt;p&gt;比如说，上面图中，我们假设只给这个进程分配了一个数据页。如果只使用页表，也需要完整的 1M 个页表项共 4M 的内存，但是如果使用了页目录，页目录需要 1K 个全部分配，占用内存 4K，但是里面只有一项使用了。到了页表项，只需要分配能够管理那个数据页的页表项页就可以了，也就是说，最多 4K，这样内存就节省多了。&lt;/p&gt;
&lt;p&gt;当然对于 64 位的系统，两级肯定不够了，就变成了四级目录，分别是全局页目录项 PGD（Page Global Directory）、上层页目录项 PUD（Page Upper Directory）、中间页目录项 PMD（Page Middle Directory）和页表项 PTE（Page Table Entry）。&lt;/p&gt;
&lt;h2 id=&#34;进程空间管理&#34;&gt;进程空间管理&lt;/h2&gt;
&lt;h2 id=&#34;物理内存管理&#34;&gt;物理内存管理&lt;/h2&gt;
&lt;h2 id=&#34;用户态内存映射&#34;&gt;用户态内存映射&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define GDT_ENTRY_INIT(flags, base, limit) { { { \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;  .a = ((limit) &amp;amp; 0xffff) | (((base) &amp;amp; 0xffff) &amp;lt;&amp;lt; 16), \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;  .b = (((base) &amp;amp; 0xff0000) &amp;gt;&amp;gt; 16) | (((flags) &amp;amp; 0xf0ff) &amp;lt;&amp;lt; 8) | \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;    ((limit) &amp;amp; 0xf0000) | ((base) &amp;amp; 0xff000000), \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;  } } }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过分析，我们发现，所有的段的起始地址都是一样的，都是 0。这算哪门子分段嘛！所以，在 Linux 操作系统中，并没有使用到全部的分段功能。那分段是不是完全没有用处呢？分段可以做权限审核，例如用户态 DPL 是 3，内核态 DPL 是 0。当用户态试图访问内核态的时候，会因为权限不足而报错。&lt;/p&gt;
&lt;p&gt;其实 Linux 倾向于另外一种从虚拟地址到物理地址的转换方式，称为分页（Paging）。&lt;/p&gt;
&lt;p&gt;对于物理内存，操作系统把它分成一块一块大小相同的页，这样更方便管理，例如有的内存页面长时间不用了，可以暂时写到硬盘上，称为换出。一旦需要的时候，再加载进来，叫作换入。这样可以扩大可用物理内存的大小，提高物理内存的利用率。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="内存管理概述">内存管理概述</h2>
<p>计算机所谓的“计算”指的是：</p>
<ul>
<li>进程和线程对于 CPU 的使用</li>
<li>对内存的管理</li>
</ul>
<h3 id="独享内存空间的原理">独享内存空间的原理</h3>
<p>每个进程都独享一段内存空间，并且真实物理内存地址对进程不可见，操作系统会给进程分配一个虚拟地址，每个进程看到的内存地址都是从 0 开始。操作系统会将不同进程的虚拟地址和不同内存的物理地址做映射。当程序访问虚拟地址时，由内核的数据结构进行转换，转换成不同的物理地址，这样不同的进程运行的时候，写入的是不同的物理地址。</p>
<h3 id="规划虚拟地址空间">规划虚拟地址空间</h3>
<p>通过以上的原理，我们可以看出，操作系统的内存管理，主要分为三个方面。</p>
<ol>
<li>物理内存的管理；</li>
<li>虚拟地址的管理；</li>
<li>虚拟地址和物理地址如何映射；</li>
</ol>
<p>进程获取了一段独立的虚拟内存空间后，可以不用管其他进程，“任意”使用这片内存，但是也有一点规则。这篇内存需要存放内核态和用户态的内容。高地址存放内核态的内容，低地址存放用户态的内容。具体分界线 64 位与 32 位不同，暂不深究。</p>
<p>我们从最低位开始排起，先是<strong>Text Segment、Data Segment 和 BSS Segment</strong>。Text Segment 是存放二进制可执行代码的位置，Data Segment 存放静态常量，BSS Segment 存放未初始化的静态变量。是不是觉得这几个名字很熟悉？没错，咱们前面讲 ELF 格式的时候提到过，在二进制执行文件里面，就有这三个部分。这里就是把二进制执行文件的三个部分加载到内存里面。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129170110.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129170110.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>接下来是<strong>堆</strong>（Heap）<strong>段</strong>。堆是往高地址增长的，是用来动态分配内存的区域，<code>malloc</code> 就是在这里面分配的。
接下来的区域是<strong>Memory Mapping Segment</strong>。这块地址可以用来把文件映射进内存用的，如果二进制的执行文件依赖于某个动态链接库，就是在这个区域里面将 so 文件映射到了内存中。
再下面就是<strong>栈</strong>（Stack）<strong>地址段</strong>。主线程的函数调用的函数栈就是用这里的。</p>
<p>普通进程不能访问内核空间，如果需要进行更高权限的工作，就需要系统调用进入内核。每一段进程的内存空间存放的内容各不相同，但是进入内核后看到的都是同一个内核空间，同一个进程列表。</p>
<p>内核的代码访问内核的数据结构，大部分的情况下都是使用虚拟地址的，虽然内核代码权限很大，但是能够使用的虚拟地址范围也只能在内核空间，也即内核代码访问内核数据结构。</p>
<p>接下来，我们需要知道，如何将其映射成为物理地址呢？</p>
<p>咱们前面讲 x86 CPU 的时候，讲过分段机制，咱们规划虚拟空间的时候，也是将空间分成多个段进行保存。我们来看看分段机制的原理。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129182908.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129182908.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>分段机制下的虚拟地址由两部分组成，<strong>段选择子</strong>和<strong>段内偏移量</strong>。段选择子就保存在咱们前面讲过的段寄存器里面。段选择子里面最重要的是<strong>段号</strong>，用作段表的索引。段表里面保存的是这个段的<strong>基地址</strong>、<strong>段的界限</strong>和<strong>特权等级</strong>等。虚拟地址中的段内偏移量应该位于 0 和段界限之间。如果段内偏移量是合法的，就将段基地址加上段内偏移量得到物理内存地址。</p>
<p>例如，我们将上面的虚拟空间分成以下 4 个段，用 0～3 来编号。每个段在段表中有一个项，在物理空间中，段的排列如下图的右边所示。如果要访问段 2 中偏移量 600 的虚拟地址，我们可以计算出物理地址为，段 2 基地址 2000 + 偏移量 600 = 2600。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129183334.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129183334.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>在 Linux 里面，段表全称<strong>段描述符表</strong>（segment descriptors），放在<strong>全局描述符表 GDT</strong>（Global Descriptor Table）里面，会有下面的宏来初始化段描述符表里面的表项。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define GDT_ENTRY_INIT(flags, base, limit) { { { \
</span></span></span><span class="line"><span class="cl"><span class="cp">    .a = ((limit) &amp; 0xffff) | (((base) &amp; 0xffff) &lt;&lt; 16), \
</span></span></span><span class="line"><span class="cl"><span class="cp">    .b = (((base) &amp; 0xff0000) &gt;&gt; 16) | (((flags) &amp; 0xf0ff) &lt;&lt; 8) | \
</span></span></span><span class="line"><span class="cl"><span class="cp">      ((limit) &amp; 0xf0000) | ((base) &amp; 0xff000000), \
</span></span></span><span class="line"><span class="cl"><span class="cp">  } } }
</span></span></span></code></pre></div><p>一个段表项由段基地址 base、段界限 limit，还有一些标识符组成。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">DEFINE_PER_CPU_PAGE_ALIGNED</span><span class="p">(</span><span class="k">struct</span> <span class="n">gdt_page</span><span class="p">,</span> <span class="n">gdt_page</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span> <span class="p">.</span><span class="n">gdt</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_X86_64
</span></span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL32_CS</span><span class="p">]</span>    <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span>    <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa09b</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span>    <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc093</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER32_CS</span><span class="p">]</span>  <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span>  <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span>  <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xa0fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_CS</span><span class="p">]</span>    <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc09a</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_KERNEL_DS</span><span class="p">]</span>    <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc092</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_CS</span><span class="p">]</span>  <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0fa</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="n">GDT_ENTRY_DEFAULT_USER_DS</span><span class="p">]</span>  <span class="o">=</span> <span class="nf">GDT_ENTRY_INIT</span><span class="p">(</span><span class="mh">0xc0f2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mh">0xfffff</span><span class="p">),</span>
</span></span><span class="line"><span class="cl"><span class="p">......</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="nf">EXPORT_PER_CPU_SYMBOL_GPL</span><span class="p">(</span><span class="n">gdt_page</span><span class="p">);</span>
</span></span></code></pre></div><p>这里面对于 64 位的和 32 位的，都定义了内核代码段、内核数据段、用户代码段和用户数据段。另外，还会定义下面四个段选择子，指向上面的段描述符表项。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define __KERNEL_CS      (GDT_ENTRY_KERNEL_CS*8)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define __KERNEL_DS      (GDT_ENTRY_KERNEL_DS*8)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define __USER_DS      (GDT_ENTRY_DEFAULT_USER_DS*8 + 3)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define __USER_CS      (GDT_ENTRY_DEFAULT_USER_CS*8 + 3)
</span></span></span></code></pre></div><p>通过分析，我们发现，所有的段的起始地址都是一样的，都是 0。所以，在 Linux 操作系统中，并没有使用到全部的分段功能。那分段是不是完全没有用处呢？分段可以做权限审核，例如用户态 DPL 是 3，内核态 DPL 是 0。当用户态试图访问内核态的时候，会因为权限不足而报错。
其实 Linux 倾向于另外一种从虚拟地址到物理地址的转换方式，称为<strong>分页</strong>（Paging）。对于物理内存，操作系统把它分成一块一块大小相同的页，这样更方便管理，例如有的内存页面长时间不用了，可以<strong>暂时写到硬盘上</strong>，称为<strong>换出</strong>。一旦需要的时候，再<strong>加载进来</strong>，叫作<strong>换入</strong>。这样可以扩大可用物理内存的大小，提高物理内存的利用率。</p>
<p>这个换入和换出都是以页为单位的。页面的大小一般为 4KB。为了能够定位和访问每个页，需要有个页表，保存每个页的起始地址，再加上在页内的偏移量，组成线性地址，就能对于内存中的每个位置进行访问了。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129185728.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129185728.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>虚拟地址分为两部分，<strong>页号</strong>和<strong>页内偏移</strong>。页号作为页表的索引，页表包含物理页每页所在物理内存的基地址。这个基地址与页内偏移的组合就形成了物理内存地址。</p>
<p>32 位环境下，虚拟地址空间共 4GB。如果分成 4KB 一个页，那就是 1M 个页。每个页表项需要 4 个字节来存储，那么整个 4GB 空间的映射就需要 4MB 的内存来存储映射表。如果每个进程都有自己的映射表，100 个进程就需要 400MB 的内存。对于内核来讲，有点大了。</p>
<p>页表中所有页表项必须提前建好，并且要求是连续的。如果不连续，就没有办法通过虚拟地址里面的页号找到对应的页表项了。</p>
<p>那怎么办呢？我们可以试着将页表再分页，4G 的空间需要 4M 的页表来存储映射。我们把这 4M 分成 1K（1024）个 4K，每个 4K 又能放在一页里面，这样 1K 个 4K 就是 1K 个页，这 1K 个页也需要一个表进行管理，我们称为页目录表，这个页目录表里面有 1K 项，每项 4 个字节，页目录表大小也是 4K。</p>
<p>页目录有 1K 项，用 10 位就可以表示访问页目录的哪一项。这一项其实对应的是一整页的页表项，也即 4K 的页表项。每个页表项也是 4 个字节，因而一整页的页表项是 1K 个。再用 10 位就可以表示访问页表项的哪一项，页表项中的一项对应的就是一个页，是存放数据的页，这个页的大小是 4K，用 12 位可以定位这个页内的任何一个位置。</p>
<p>这样加起来正好 32 位，也就是用前 10 位定位到页目录表中的一项。将这一项对应的页表取出来共 1k 项，再用中间 10 位定位到页表中的一项，将这一项对应的存放数据的页取出来，再用最后 12 位定位到页中的具体位置访问数据。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129192245.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20211129192245.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>你可能会问，如果这样的话，映射 4GB 地址空间就需要 4MB+4KB 的内存，这样不是更大了吗？当然如果页是满的，当时是更大了，但是，我们往往不会为一个进程分配那么多内存。</p>
<p>比如说，上面图中，我们假设只给这个进程分配了一个数据页。如果只使用页表，也需要完整的 1M 个页表项共 4M 的内存，但是如果使用了页目录，页目录需要 1K 个全部分配，占用内存 4K，但是里面只有一项使用了。到了页表项，只需要分配能够管理那个数据页的页表项页就可以了，也就是说，最多 4K，这样内存就节省多了。</p>
<p>当然对于 64 位的系统，两级肯定不够了，就变成了四级目录，分别是全局页目录项 PGD（Page Global Directory）、上层页目录项 PUD（Page Upper Directory）、中间页目录项 PMD（Page Middle Directory）和页表项 PTE（Page Table Entry）。</p>
<h2 id="进程空间管理">进程空间管理</h2>
<h2 id="物理内存管理">物理内存管理</h2>
<h2 id="用户态内存映射">用户态内存映射</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define GDT_ENTRY_INIT(flags, base, limit) { { { \
</span></span></span><span class="line"><span class="cl"><span class="cp">  .a = ((limit) &amp; 0xffff) | (((base) &amp; 0xffff) &lt;&lt; 16), \
</span></span></span><span class="line"><span class="cl"><span class="cp">  .b = (((base) &amp; 0xff0000) &gt;&gt; 16) | (((flags) &amp; 0xf0ff) &lt;&lt; 8) | \
</span></span></span><span class="line"><span class="cl"><span class="cp">    ((limit) &amp; 0xf0000) | ((base) &amp; 0xff000000), \
</span></span></span><span class="line"><span class="cl"><span class="cp">  } } }
</span></span></span></code></pre></div><p>通过分析，我们发现，所有的段的起始地址都是一样的，都是 0。这算哪门子分段嘛！所以，在 Linux 操作系统中，并没有使用到全部的分段功能。那分段是不是完全没有用处呢？分段可以做权限审核，例如用户态 DPL 是 3，内核态 DPL 是 0。当用户态试图访问内核态的时候，会因为权限不足而报错。</p>
<p>其实 Linux 倾向于另外一种从虚拟地址到物理地址的转换方式，称为分页（Paging）。</p>
<p>对于物理内存，操作系统把它分成一块一块大小相同的页，这样更方便管理，例如有的内存页面长时间不用了，可以暂时写到硬盘上，称为换出。一旦需要的时候，再加载进来，叫作换入。这样可以扩大可用物理内存的大小，提高物理内存的利用率。</p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux 操作系统-进程间通信</title>
      <link>https://lifeislife.cn/posts/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/</link>
      <pubDate>Sat, 14 Aug 2021 09:46:39 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/</guid>
      <description>&lt;p&gt;Linux 环境下，进程地址空间相互独立，每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到，所以进程和进程之间不能相互访问，要交换数据必须通过内核，在内核中开辟一块缓冲区，进程 1 把数据从用户空间拷到内核缓冲区，进程 2 再从内核缓冲区把数据读走，内核提供的这种机制称为&lt;strong&gt;进程间通信（IPC，InterProcess Communication）&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;进程间通信概述&#34;&gt;进程间通信概述&lt;/h2&gt;
&lt;h3 id=&#34;管道&#34;&gt;管道&lt;/h3&gt;
&lt;p&gt;在学 Linux 命令时就有管道在这个概念，比如下面这个命令&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ps -ef  | -grep root | xargs kill -9
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将上一个命令的输出作为下一个命令的输入，数据只能向一个方向流动；双方需要互相通信时，需要建立起两个管道。&lt;/p&gt;
&lt;p&gt;管道有两种类型：匿名管道和命名管道。上面提到的命令中&lt;code&gt;|&lt;/code&gt;表示的管道即&lt;strong&gt;匿名管道 pipe&lt;/strong&gt;。用完即销毁，自动创建，自动销毁。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;mkfifo&lt;/code&gt;显示创建的是&lt;strong&gt;命名管道 fifo&lt;/strong&gt;，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkfifo hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;hello&lt;/code&gt;即是管道名称，类型为&lt;code&gt;p&lt;/code&gt;，就是&lt;code&gt;pipe&lt;/code&gt;，接下来就可以在管道里写入东西，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# echo &amp;#34;hello world&amp;#34; &amp;gt; hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;光写入还不行，只有有另一个进程读取了内容才完成一次信息交换，才完成一次通信，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# cat &amp;lt; hello 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;hello world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这种方式通信效率低，无法频繁通信。&lt;/p&gt;
&lt;h3 id=&#34;消息队列&#34;&gt;消息队列&lt;/h3&gt;
&lt;p&gt;类似于日常沟通使用的邮件，有一定格式，有个收件列表，列表上的用户都可以反复在原邮件基础上回复，达到频繁交流的目的。这种模型就是&lt;strong&gt;消息队列模型&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;共享内存&#34;&gt;共享内存&lt;/h3&gt;
&lt;p&gt;共享内存允许两个或多个进程共享一个给定的存储区，这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中，一个进程写入共享内存的信息，可以被其他使用这个共享内存的进程，通过一个简单的内存读取错做读出，从而实现了进程间的通信。&lt;/p&gt;
&lt;p&gt;每个进程都有自己独立的虚拟内存空间，不同进程的虚拟内存空间映射到不同的物理内存中去。这个进程访问 A 地址和另一个进程访问 A 地址，其实访问的是不同的物理内存地址，对于数据的增删查改互不影响。&lt;/p&gt;
&lt;p&gt;但是，咱们是不是可以变通一下，&lt;strong&gt;拿出一块虚拟地址空间来，映射到相同的物理内存中&lt;/strong&gt;。这样这个进程写入的东西，另外一个进程马上就能看到了，都不需要拷贝来拷贝去，传来传去。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;shmget&lt;/code&gt;函数创建一个共享内存，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//key_t key:  唯一定位一个共享内存对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//size_t size: 共享内存大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//int flag: 如果是 IPC_CREAT 表示创建新的共享内存空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shmget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;创建完毕之后，我们可以通过 &lt;code&gt;ipcs&lt;/code&gt; 命令查看这个共享内存。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#ipcs ­­--shmems
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;------ Shared Memory Segments ------ ­­­­­­­­
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;key        shmid    owner perms    bytes nattch status
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 19398656 marc  600    1048576 2      dest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进程通过&lt;code&gt;shmat&lt;/code&gt;，就是&lt;code&gt;attach&lt;/code&gt;的意思，将内存加载到自己虚拟地址空间某个位置。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//int shm_id:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//const void *addr: 加载的地址，通常设为 NULL，让内核选一个合适地址
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//int flag:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;shmat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shm_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果共享内存使用完毕，可以通过 &lt;code&gt;shmdt&lt;/code&gt; 解除绑定，然后通过 &lt;code&gt;shmctl&lt;/code&gt;，将 &lt;code&gt;cmd&lt;/code&gt; 设置为 &lt;code&gt;IPC_RMID&lt;/code&gt;，从而删除这个共享内存对象。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shmdt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shmctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shm_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmid_ds&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;共享内存的最大不足之处在于，由于多个进程对同一块内存区具有访问的权限，各个进程之间的同步问题显得尤为突出。必须控制同一时刻只有一个进程对共享内存区域写入数据，否则将造成数据的混乱。&lt;/p&gt;
&lt;h3 id=&#34;信号量&#34;&gt;信号量&lt;/h3&gt;
&lt;p&gt;如果两个进程同时向一个共享内存读写数据，很可能就会导致冲突。所以需要有一种保护机制，使得同一个共享资源同时只能被一个进程访问。在进程间通信机制中，&lt;strong&gt;信号量&lt;/strong&gt;（Semaphore）就是用来实现进程间互斥与同步的。它其实是个&lt;strong&gt;计数器&lt;/strong&gt;，只不过不是用来记录进程间通信数据的。&lt;/p&gt;
&lt;p&gt;我们可以将信号量初始化为一个数值，来代表某种资源的总体数量。对于信号量来讲，会定义两种原子操作，一个是&lt;code&gt;P&lt;/code&gt; 操作，我们称为&lt;strong&gt;申请资源操作&lt;/strong&gt;。这个操作会申请将信号量的数值&lt;strong&gt;减去&lt;/strong&gt; N，表示这些数量被他申请使用了，其他人不能用了。另一个是&lt;code&gt;V&lt;/code&gt;操作，我们称为&lt;strong&gt;归还资源操作&lt;/strong&gt;，这个操作会申请将信号量&lt;strong&gt;加上&lt;/strong&gt; M，表示这些数量已经还给信号量了，其他人可以使用了。&lt;/p&gt;
&lt;p&gt;所谓&lt;strong&gt;原子操作&lt;/strong&gt;（Atom Operation）就是不可被中断的一个或一系列操作。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;semget&lt;/code&gt;&lt;strong&gt;创建&lt;/strong&gt;信号量，第一个参数表示唯一标识，第二个参数表示可以创建多少个信号量。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;semget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_sems&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下来，我们需要&lt;strong&gt;初始化&lt;/strong&gt;信号量的总的资源数量。通过&lt;code&gt;semctl&lt;/code&gt; 函数，第一个参数 &lt;code&gt;semid&lt;/code&gt;是这个信号量组的&lt;code&gt;id&lt;/code&gt;，第二个参数 &lt;code&gt;semnum&lt;/code&gt; 才是在这个信号量组中某个信号量的&lt;code&gt;id&lt;/code&gt;，第三个参数是命令，如果是初始化，则用 &lt;code&gt;SETVAL&lt;/code&gt;，第四个参数是一个 &lt;code&gt;union&lt;/code&gt;。如果初始化，应该用里面的&lt;code&gt;val&lt;/code&gt;设置资源总量。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;semctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semnum&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;union&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semun&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;union&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semun&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semid_ds&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;array&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;seminfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;无论是 P 操作还是 V 操作，我们统一用 semop 函数。第一个参数还是信号量组的 id，一次可以操作多个信号量。第三个参数 numops 就是有多少个操作，第二个参数将这些操作放在一个数组中。&lt;/p&gt;
&lt;p&gt;数组的每一项是一个 &lt;code&gt;struct sembuf&lt;/code&gt;，里面的第一个成员是这个操作的对象是哪个信号量。第二个成员就是要对这个信号量做多少改变。如果 &lt;code&gt;sem_op &amp;lt; 0&lt;/code&gt;，就请求 &lt;code&gt;sem_op&lt;/code&gt; 的绝对值的资源。如果相应的资源数可以满足请求，则将该信号量的值减去 &lt;code&gt;sem_op&lt;/code&gt; 的绝对值，函数成功返回。&lt;/p&gt;
&lt;p&gt;当相应的资源数不能满足请求时，就要看&lt;code&gt;sem_flg&lt;/code&gt; 了。如果把 &lt;code&gt;sem_flg&lt;/code&gt; 设置为&lt;code&gt;IPC_NOWAIT&lt;/code&gt;，也就是没有资源也不等待，则 &lt;code&gt;semop&lt;/code&gt; 函数出错返回 &lt;code&gt;EAGAIN&lt;/code&gt;。如果 &lt;code&gt;sem_flg&lt;/code&gt; 没有指定&lt;code&gt;IPC_NOWAIT&lt;/code&gt;，则进程挂起，直到当相应的资源数可以满足请求。若 &lt;code&gt;sem_op &amp;gt; 0&lt;/code&gt;，表示进程归还相应的资源数，将 &lt;code&gt;sem_op&lt;/code&gt; 的值加到信号量的值上。如果有进程正在休眠等待此信号量，则唤醒它们。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;semop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sembuf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semoparray&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;numops&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sembuf&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 信号量组中对应的序号，0～sem_nums-1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 信号量值在一次操作中的改变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kt&#34;&gt;short&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sem_flg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// IPC_NOWAIT, SEM_UNDO
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;信号&#34;&gt;信号&lt;/h3&gt;
&lt;p&gt;以上提到的通信方式，都是常规状态下的工作模式，而信号一般是由&lt;strong&gt;错误&lt;/strong&gt;产生的。&lt;/p&gt;
&lt;p&gt;信号没有特别复杂的数据结构，就是用一个代号一样的数字。Linux 提供了几十种信号，分别代表不同的意义。信号之间依靠它们的值来区分。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>Linux 环境下，进程地址空间相互独立，每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到，所以进程和进程之间不能相互访问，要交换数据必须通过内核，在内核中开辟一块缓冲区，进程 1 把数据从用户空间拷到内核缓冲区，进程 2 再从内核缓冲区把数据读走，内核提供的这种机制称为<strong>进程间通信（IPC，InterProcess Communication）</strong>。</p>
<h2 id="进程间通信概述">进程间通信概述</h2>
<h3 id="管道">管道</h3>
<p>在学 Linux 命令时就有管道在这个概念，比如下面这个命令</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ps -ef  | -grep root | xargs kill -9
</span></span></code></pre></div><p>将上一个命令的输出作为下一个命令的输入，数据只能向一个方向流动；双方需要互相通信时，需要建立起两个管道。</p>
<p>管道有两种类型：匿名管道和命名管道。上面提到的命令中<code>|</code>表示的管道即<strong>匿名管道 pipe</strong>。用完即销毁，自动创建，自动销毁。</p>
<p>使用<code>mkfifo</code>显示创建的是<strong>命名管道 fifo</strong>，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">mkfifo hello
</span></span></code></pre></div><p><code>hello</code>即是管道名称，类型为<code>p</code>，就是<code>pipe</code>，接下来就可以在管道里写入东西，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># echo &#34;hello world&#34; &gt; hello
</span></span></code></pre></div><p>光写入还不行，只有有另一个进程读取了内容才完成一次信息交换，才完成一次通信，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># cat &lt; hello 
</span></span><span class="line"><span class="cl">hello world
</span></span></code></pre></div><p>这种方式通信效率低，无法频繁通信。</p>
<h3 id="消息队列">消息队列</h3>
<p>类似于日常沟通使用的邮件，有一定格式，有个收件列表，列表上的用户都可以反复在原邮件基础上回复，达到频繁交流的目的。这种模型就是<strong>消息队列模型</strong>。</p>
<h3 id="共享内存">共享内存</h3>
<p>共享内存允许两个或多个进程共享一个给定的存储区，这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中，一个进程写入共享内存的信息，可以被其他使用这个共享内存的进程，通过一个简单的内存读取错做读出，从而实现了进程间的通信。</p>
<p>每个进程都有自己独立的虚拟内存空间，不同进程的虚拟内存空间映射到不同的物理内存中去。这个进程访问 A 地址和另一个进程访问 A 地址，其实访问的是不同的物理内存地址，对于数据的增删查改互不影响。</p>
<p>但是，咱们是不是可以变通一下，<strong>拿出一块虚拟地址空间来，映射到相同的物理内存中</strong>。这样这个进程写入的东西，另外一个进程马上就能看到了，都不需要拷贝来拷贝去，传来传去。</p>
<p>使用<code>shmget</code>函数创建一个共享内存，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//key_t key:  唯一定位一个共享内存对象
</span></span></span><span class="line"><span class="cl"><span class="c1">//size_t size: 共享内存大小
</span></span></span><span class="line"><span class="cl"><span class="c1">//int flag: 如果是 IPC_CREAT 表示创建新的共享内存空间
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">shmget</span><span class="p">(</span><span class="kt">key_t</span> <span class="n">key</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flag</span><span class="p">);</span>
</span></span></code></pre></div><p>创建完毕之后，我们可以通过 <code>ipcs</code> 命令查看这个共享内存。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">#ipcs ­­--shmems
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">------ Shared Memory Segments ------ ­­­­­­­­
</span></span><span class="line"><span class="cl">key        shmid    owner perms    bytes nattch status
</span></span><span class="line"><span class="cl">0x00000000 19398656 marc  600    1048576 2      dest
</span></span></code></pre></div><p>进程通过<code>shmat</code>，就是<code>attach</code>的意思，将内存加载到自己虚拟地址空间某个位置。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//int shm_id:
</span></span></span><span class="line"><span class="cl"><span class="c1">//const void *addr: 加载的地址，通常设为 NULL，让内核选一个合适地址
</span></span></span><span class="line"><span class="cl"><span class="c1">//int flag:
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="nf">shmat</span><span class="p">(</span><span class="kt">int</span> <span class="n">shm_id</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flag</span><span class="p">);</span>
</span></span></code></pre></div><p>如果共享内存使用完毕，可以通过 <code>shmdt</code> 解除绑定，然后通过 <code>shmctl</code>，将 <code>cmd</code> 设置为 <code>IPC_RMID</code>，从而删除这个共享内存对象。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">shmdt</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">addr</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">shmctl</span><span class="p">(</span><span class="kt">int</span> <span class="n">shm_id</span><span class="p">,</span> <span class="kt">int</span> <span class="n">cmd</span><span class="p">,</span> <span class="k">struct</span> <span class="n">shmid_ds</span> <span class="o">*</span><span class="n">buf</span><span class="p">);</span>
</span></span></code></pre></div><p>共享内存的最大不足之处在于，由于多个进程对同一块内存区具有访问的权限，各个进程之间的同步问题显得尤为突出。必须控制同一时刻只有一个进程对共享内存区域写入数据，否则将造成数据的混乱。</p>
<h3 id="信号量">信号量</h3>
<p>如果两个进程同时向一个共享内存读写数据，很可能就会导致冲突。所以需要有一种保护机制，使得同一个共享资源同时只能被一个进程访问。在进程间通信机制中，<strong>信号量</strong>（Semaphore）就是用来实现进程间互斥与同步的。它其实是个<strong>计数器</strong>，只不过不是用来记录进程间通信数据的。</p>
<p>我们可以将信号量初始化为一个数值，来代表某种资源的总体数量。对于信号量来讲，会定义两种原子操作，一个是<code>P</code> 操作，我们称为<strong>申请资源操作</strong>。这个操作会申请将信号量的数值<strong>减去</strong> N，表示这些数量被他申请使用了，其他人不能用了。另一个是<code>V</code>操作，我们称为<strong>归还资源操作</strong>，这个操作会申请将信号量<strong>加上</strong> M，表示这些数量已经还给信号量了，其他人可以使用了。</p>
<p>所谓<strong>原子操作</strong>（Atom Operation）就是不可被中断的一个或一系列操作。</p>
<p>使用<code>semget</code><strong>创建</strong>信号量，第一个参数表示唯一标识，第二个参数表示可以创建多少个信号量。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">semget</span><span class="p">(</span><span class="kt">key_t</span> <span class="n">key</span><span class="p">,</span> <span class="kt">int</span> <span class="n">num_sems</span><span class="p">,</span> <span class="kt">int</span> <span class="n">sem_flags</span><span class="p">);</span>
</span></span></code></pre></div><p>接下来，我们需要<strong>初始化</strong>信号量的总的资源数量。通过<code>semctl</code> 函数，第一个参数 <code>semid</code>是这个信号量组的<code>id</code>，第二个参数 <code>semnum</code> 才是在这个信号量组中某个信号量的<code>id</code>，第三个参数是命令，如果是初始化，则用 <code>SETVAL</code>，第四个参数是一个 <code>union</code>。如果初始化，应该用里面的<code>val</code>设置资源总量。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">semctl</span><span class="p">(</span><span class="kt">int</span> <span class="n">semid</span><span class="p">,</span> <span class="kt">int</span> <span class="n">semnum</span><span class="p">,</span> <span class="kt">int</span> <span class="n">cmd</span><span class="p">,</span> <span class="k">union</span> <span class="n">semun</span> <span class="n">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="k">union</span> <span class="n">semun</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kt">int</span> <span class="n">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">struct</span> <span class="n">semid_ds</span> <span class="o">*</span><span class="n">buf</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kt">unsigned</span> <span class="kt">short</span> <span class="kt">int</span> <span class="o">*</span><span class="n">array</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">struct</span> <span class="n">seminfo</span> <span class="o">*</span><span class="n">__buf</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>无论是 P 操作还是 V 操作，我们统一用 semop 函数。第一个参数还是信号量组的 id，一次可以操作多个信号量。第三个参数 numops 就是有多少个操作，第二个参数将这些操作放在一个数组中。</p>
<p>数组的每一项是一个 <code>struct sembuf</code>，里面的第一个成员是这个操作的对象是哪个信号量。第二个成员就是要对这个信号量做多少改变。如果 <code>sem_op &lt; 0</code>，就请求 <code>sem_op</code> 的绝对值的资源。如果相应的资源数可以满足请求，则将该信号量的值减去 <code>sem_op</code> 的绝对值，函数成功返回。</p>
<p>当相应的资源数不能满足请求时，就要看<code>sem_flg</code> 了。如果把 <code>sem_flg</code> 设置为<code>IPC_NOWAIT</code>，也就是没有资源也不等待，则 <code>semop</code> 函数出错返回 <code>EAGAIN</code>。如果 <code>sem_flg</code> 没有指定<code>IPC_NOWAIT</code>，则进程挂起，直到当相应的资源数可以满足请求。若 <code>sem_op &gt; 0</code>，表示进程归还相应的资源数，将 <code>sem_op</code> 的值加到信号量的值上。如果有进程正在休眠等待此信号量，则唤醒它们。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">semop</span><span class="p">(</span><span class="kt">int</span> <span class="n">semid</span><span class="p">,</span> <span class="k">struct</span> <span class="n">sembuf</span> <span class="n">semoparray</span><span class="p">[],</span> <span class="kt">size_t</span>  <span class="n">numops</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sembuf</span> 
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kt">short</span> <span class="n">sem_num</span><span class="p">;</span> <span class="c1">// 信号量组中对应的序号，0～sem_nums-1
</span></span></span><span class="line"><span class="cl">  <span class="kt">short</span> <span class="n">sem_op</span><span class="p">;</span>  <span class="c1">// 信号量值在一次操作中的改变量
</span></span></span><span class="line"><span class="cl">  <span class="kt">short</span> <span class="n">sem_flg</span><span class="p">;</span> <span class="c1">// IPC_NOWAIT, SEM_UNDO
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="信号">信号</h3>
<p>以上提到的通信方式，都是常规状态下的工作模式，而信号一般是由<strong>错误</strong>产生的。</p>
<p>信号没有特别复杂的数据结构，就是用一个代号一样的数字。Linux 提供了几十种信号，分别代表不同的意义。信号之间依靠它们的值来区分。</p>
]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-rename 批量重命名</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-rename%E6%89%B9%E9%87%8F%E9%87%8D%E5%91%BD%E5%90%8D/</link>
      <pubDate>Fri, 13 Aug 2021 18:40:16 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-rename%E6%89%B9%E9%87%8F%E9%87%8D%E5%91%BD%E5%90%8D/</guid>
      <description>&lt;h2 id=&#34;commands&#34;&gt;Commands&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rename [options] &amp;#34;s/oldname/newname/&amp;#34; file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;格式就很容易看出来怎么用的，就是&lt;code&gt;/&lt;/code&gt;不能丢。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-v 将重命名的内容都打印到标准输出，v 可以看成 verbose
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-n 测试会重命名的内容，将结果都打印，但是并不真正执行重命名的过程
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-f force 会覆盖本地已经存在的文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-h -m -V 分别为帮助，帮助，版本
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-e 比较复杂，可以通过该选项，写一些脚本来做一些复杂的事情
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;
&lt;h3 id=&#34;替换文件名中的特定字段&#34;&gt;替换文件名中的特定字段&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rename &amp;#34;s/AA/aa/&amp;#34; *  # 把文件名中的AA替换成aa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;修改文件后缀&#34;&gt;修改文件后缀&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rename &amp;#34;s/.html/.php/&amp;#34; *     # 把.html 后缀的改成 .php后缀
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rename &amp;#34;s/.png/.jpg/&amp;#34; *      # 将 png 改为 jpg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;添加后缀&#34;&gt;添加后缀&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rename &amp;#34;s/$/.txt/&amp;#34; *     # 把所有的文件名都以txt结尾
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;$&lt;/code&gt;正则表达式中表示结尾。&lt;/p&gt;
&lt;h3 id=&#34;保留部分文件名&#34;&gt;保留部分文件名&lt;/h3&gt;
&lt;p&gt;假如需要在批量修改的时候保留部分文件名，可以使用引用&lt;code&gt;\1&lt;/code&gt; ，比如有下面格式的文件，只想保留日期部分。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Screenshot from 2019-01-02 15-56-49.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rename -n &amp;#34;s/Screenshot from ([0-9\\- ]+).jpg/\1.jpg/&amp;#34; *
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将&lt;code&gt;()&lt;/code&gt; 匹配的内容取出来放到替换部分。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="commands">Commands</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">rename [options] &#34;s/oldname/newname/&#34; file
</span></span></code></pre></div><p>格式就很容易看出来怎么用的，就是<code>/</code>不能丢。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">-v 将重命名的内容都打印到标准输出，v 可以看成 verbose
</span></span><span class="line"><span class="cl">-n 测试会重命名的内容，将结果都打印，但是并不真正执行重命名的过程
</span></span><span class="line"><span class="cl">-f force 会覆盖本地已经存在的文件
</span></span><span class="line"><span class="cl">-h -m -V 分别为帮助，帮助，版本
</span></span><span class="line"><span class="cl">-e 比较复杂，可以通过该选项，写一些脚本来做一些复杂的事情
</span></span></code></pre></div><h2 id="examples">Examples</h2>
<h3 id="替换文件名中的特定字段">替换文件名中的特定字段</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">rename &#34;s/AA/aa/&#34; *  # 把文件名中的AA替换成aa
</span></span></code></pre></div><h3 id="修改文件后缀">修改文件后缀</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">rename &#34;s/.html/.php/&#34; *     # 把.html 后缀的改成 .php后缀
</span></span><span class="line"><span class="cl">rename &#34;s/.png/.jpg/&#34; *      # 将 png 改为 jpg
</span></span></code></pre></div><h3 id="添加后缀">添加后缀</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">rename &#34;s/$/.txt/&#34; *     # 把所有的文件名都以txt结尾
</span></span></code></pre></div><p><code>$</code>正则表达式中表示结尾。</p>
<h3 id="保留部分文件名">保留部分文件名</h3>
<p>假如需要在批量修改的时候保留部分文件名，可以使用引用<code>\1</code> ，比如有下面格式的文件，只想保留日期部分。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Screenshot from 2019-01-02 15-56-49.jpg
</span></span><span class="line"><span class="cl">rename -n &#34;s/Screenshot from ([0-9\\- ]+).jpg/\1.jpg/&#34; *
</span></span></code></pre></div><p>将<code>()</code> 匹配的内容取出来放到替换部分。</p>
]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-apt 安装卸载软件</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-apt%E5%AE%89%E8%A3%85%E5%8D%B8%E8%BD%BD%E8%BD%AF%E4%BB%B6/</link>
      <pubDate>Thu, 12 Aug 2021 18:42:39 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-apt%E5%AE%89%E8%A3%85%E5%8D%B8%E8%BD%BD%E8%BD%AF%E4%BB%B6/</guid>
      <description>&lt;p&gt;这个命令应该是我们平时用的最多的命令之一了，应该早就拿出来讲一下的。但是平时用的太多，总感觉自己都会用了，但是仔细看了所有命令，还是有一些比较实用但是没记住的命令。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;apt&lt;/code&gt;的全称是&lt;code&gt;Advanced Packaging Tool&lt;/code&gt;是 Linux 系统下的一款安装包管理工具。APT 可以自动下载、配置和安装二进制或源代码格式软件包，简化了 Unix 系统上管理软件的过程。&lt;/p&gt;
&lt;p&gt;APT 主要由以下几个命令组成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-cache
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-file
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;commands&#34;&gt;Commands&lt;/h2&gt;
&lt;h3 id=&#34;搜索软件包&#34;&gt;搜索软件包&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt search python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;安装软件包&#34;&gt;安装软件包&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt install python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;更新源&#34;&gt;更新源&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;更新软件&#34;&gt;更新软件&lt;/h3&gt;
&lt;p&gt;执行完 update 命令后，就可以使用 apt upgrade 来升级软件包了。执行命令后系统会提示有几个软件需要升级。在得到你的同意后，系统即开始自动下载安装软件包。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;卸载软件&#34;&gt;卸载软件&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt remove python3  # 移除软件包，但是保留配置文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt purge python3 #移除软件包并移除配置
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt autoremove # 移除孤立的并不被依赖的软件包
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;列出软件清单&#34;&gt;列出软件清单&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>这个命令应该是我们平时用的最多的命令之一了，应该早就拿出来讲一下的。但是平时用的太多，总感觉自己都会用了，但是仔细看了所有命令，还是有一些比较实用但是没记住的命令。</p>
<p><code>apt</code>的全称是<code>Advanced Packaging Tool</code>是 Linux 系统下的一款安装包管理工具。APT 可以自动下载、配置和安装二进制或源代码格式软件包，简化了 Unix 系统上管理软件的过程。</p>
<p>APT 主要由以下几个命令组成：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt-get
</span></span><span class="line"><span class="cl">apt-cache
</span></span><span class="line"><span class="cl">apt-file
</span></span></code></pre></div><h2 id="commands">Commands</h2>
<h3 id="搜索软件包">搜索软件包</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt search python3
</span></span></code></pre></div><h3 id="安装软件包">安装软件包</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt install python3
</span></span></code></pre></div><h3 id="更新源">更新源</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo apt install update
</span></span></code></pre></div><h3 id="更新软件">更新软件</h3>
<p>执行完 update 命令后，就可以使用 apt upgrade 来升级软件包了。执行命令后系统会提示有几个软件需要升级。在得到你的同意后，系统即开始自动下载安装软件包。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo apt install upgrade
</span></span></code></pre></div><h3 id="卸载软件">卸载软件</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt remove python3  # 移除软件包，但是保留配置文件
</span></span><span class="line"><span class="cl">apt purge python3 #移除软件包并移除配置
</span></span><span class="line"><span class="cl">apt autoremove # 移除孤立的并不被依赖的软件包
</span></span></code></pre></div><h3 id="列出软件清单">列出软件清单</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt list
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-kill 这个进程</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-kill%E8%BF%99%E4%B8%AA%E8%BF%9B%E7%A8%8B/</link>
      <pubDate>Wed, 11 Aug 2021 15:22:40 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-kill%E8%BF%99%E4%B8%AA%E8%BF%9B%E7%A8%8B/</guid>
      <description>&lt;p&gt;对于在前台运行的程序，我们可以用&lt;code&gt;Ctrl+C&lt;/code&gt;来终止运行，但是在后台的程序就必须用&lt;code&gt;kill&lt;/code&gt;命令来终止了。&lt;/p&gt;
&lt;h2 id=&#34;command&#34;&gt;Command&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-l  信号，若果不加信号的编号参数，则使用“-l”参数会列出全部的信号名称
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-a  当处理当前进程时，不限制命令名和进程号的对应关系
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-p  指定 kill 命令只打印相关进程的进程号，而不发送任何信号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-s  指定发送信号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-u  指定用户
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;
&lt;h3 id=&#34;查看所有信号&#34;&gt;查看所有信号&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜   kill -l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;常用信号&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;HUP    1    终端断线
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;INT     2    中断（同 Ctrl + C）
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;QUIT    3    退出（同 Ctrl + \）
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;TERM   15    终止
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;KILL    9    强制终止
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;CONT   18    继续（与 STOP 相反， fg/bg 命令）
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;STOP    19    暂停（同 Ctrl + Z）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;用-ps-查找进程然后用-kill-杀掉&#34;&gt;用 ps 查找进程，然后用 kill 杀掉&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ps -ef | grep &amp;#39;program&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kill PID
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;无条件彻底杀死进程&#34;&gt;无条件彻底杀死进程&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kill –9 PID
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;杀死指定用户所有进程&#34;&gt;杀死指定用户所有进程&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kill -9 $(ps -ef | grep username)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kill -u username
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>对于在前台运行的程序，我们可以用<code>Ctrl+C</code>来终止运行，但是在后台的程序就必须用<code>kill</code>命令来终止了。</p>
<h2 id="command">Command</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">-l  信号，若果不加信号的编号参数，则使用“-l”参数会列出全部的信号名称
</span></span><span class="line"><span class="cl">-a  当处理当前进程时，不限制命令名和进程号的对应关系
</span></span><span class="line"><span class="cl">-p  指定 kill 命令只打印相关进程的进程号，而不发送任何信号
</span></span><span class="line"><span class="cl">-s  指定发送信号
</span></span><span class="line"><span class="cl">-u  指定用户
</span></span></code></pre></div><h2 id="examples">Examples</h2>
<h3 id="查看所有信号">查看所有信号</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜   kill -l
</span></span><span class="line"><span class="cl">HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 
</span></span><span class="line"><span class="cl">SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP 
</span></span><span class="line"><span class="cl">TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS
</span></span></code></pre></div><p>常用信号</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">HUP    1    终端断线
</span></span><span class="line"><span class="cl">INT     2    中断（同 Ctrl + C）
</span></span><span class="line"><span class="cl">QUIT    3    退出（同 Ctrl + \）
</span></span><span class="line"><span class="cl">TERM   15    终止
</span></span><span class="line"><span class="cl">KILL    9    强制终止
</span></span><span class="line"><span class="cl">CONT   18    继续（与 STOP 相反， fg/bg 命令）
</span></span><span class="line"><span class="cl">STOP    19    暂停（同 Ctrl + Z）
</span></span></code></pre></div><h3 id="用-ps-查找进程然后用-kill-杀掉">用 ps 查找进程，然后用 kill 杀掉</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ps -ef | grep &#39;program&#39;
</span></span><span class="line"><span class="cl">kill PID
</span></span></code></pre></div><h3 id="无条件彻底杀死进程">无条件彻底杀死进程</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">kill –9 PID
</span></span></code></pre></div><h3 id="杀死指定用户所有进程">杀死指定用户所有进程</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">kill -9 $(ps -ef | grep username)
</span></span><span class="line"><span class="cl">kill -u username
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>进程间通信（IPC）之信号（Signal）</title>
      <link>https://lifeislife.cn/posts/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1ipc%E4%B9%8B%E4%BF%A1%E5%8F%B7signal/</link>
      <pubDate>Wed, 11 Aug 2021 10:59:22 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1ipc%E4%B9%8B%E4%BF%A1%E5%8F%B7signal/</guid>
      <description>&lt;p&gt;关于进程间通信的概述可以查看&lt;a href=&#34;https://dunky-z.github.io/2021/08/10/Linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/&#34;&gt;Linux 操作系统 - 进程间通信&lt;/a&gt;，&lt;a href=&#34;https://github.com/Dunky-Z/learning-linux/tree/main/IPC/SharedMemory&#34;&gt;代码同步在这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;本文通过实例介绍通过共享内存实现进程间通信。&lt;/p&gt;
&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;
&lt;p&gt;信号就像实际生产过程中的应急预案，发生了某个异常就会启动特定的应急预案，为了响应各类异常情况，所以就定义了很多个信号，信号的名称是在头文件&lt;code&gt;signal.h&lt;/code&gt;中定义的，信号都以&lt;code&gt;SIG&lt;/code&gt;开头，常用的信号并不多，常用的信号如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIGALRM     #时钟定时信号, 计算的是实际的时间或时钟时间
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIGHUP      #终端的挂断或进程死亡
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIGINT      #来自键盘的中断信号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIGKILL     #用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIGPIPE     #管道破裂
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIGTERM     #程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIGUSR1,SIGUSR2     #留给用户使用
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;实例&#34;&gt;实例&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;signal.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;signalHandler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;Ops! - I got signal %d&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 恢复终端中断信号 SIGINT 的默认行为
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SIGINT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SIG_DFL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 改变终端中断信号 SIGINT 的默认行为，使之执行 ouch 函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 而不是终止程序的执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SIGINT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;signalHandler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Hello World!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以用&lt;code&gt;signal()&lt;/code&gt;函数处理指定的信号，主要通过忽略和恢复其默认行为来工作。signal() 函数的原型如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;signal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是一个相当复杂的声明，耐心点看可以知道 signal 是一个带有&lt;code&gt;sig&lt;/code&gt;和&lt;code&gt;func&lt;/code&gt;两个参数的函数，&lt;code&gt;func&lt;/code&gt;是一个类型为&lt;code&gt;void (*)(int)&lt;/code&gt;的函数指针。该函数返回一个与&lt;code&gt;func&lt;/code&gt;相同类型的指针，指向先前指定信号处理函数的函数指针。准备捕获的信号的参数由&lt;code&gt;sig&lt;/code&gt;给出，接收到的指定信号后要调用的函数由参数&lt;code&gt;func&lt;/code&gt;给出。其实这个函数的使用是相当简单的，通过下面的例子就可以知道。注意信号处理函数的原型必须为&lt;code&gt;void func（int）&lt;/code&gt;，或者是下面的特殊值：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIG_IGN : 忽略信号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SIG_DFL : 恢复信号的默认行为
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们程序的目的是想要捕获键盘输入&lt;code&gt;Ctrl+C&lt;/code&gt;，这个中断。通过表里可以查到，我们使用&lt;code&gt;SIGINT&lt;/code&gt;这个信号，当我们的程序出现&lt;code&gt;SIGINT&lt;/code&gt;信号时，让程序接下来干啥呢？正常情况下，我们的&lt;code&gt;Ctrl+C&lt;/code&gt;会中断当前运行的程序，但是现在我们做了一些更改，更改的内容在我们自己编写的&lt;code&gt;signalHandler&lt;/code&gt;中。我们让程序输出一行字符串加上信号值。然后再把信号的行为恢复原样。此时我们运行程序可以得到如下&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210811143147.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210811143147.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;在我们第一输入&lt;code&gt;Ctrl+C&lt;/code&gt;时，程序没有中断，而是调用了&lt;code&gt;signalHanlder&lt;/code&gt;函数，因为我们更改了信号的行为。但是第二次输入&lt;code&gt;Ctrl+C&lt;/code&gt;时，程序中断了。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>关于进程间通信的概述可以查看<a href="https://dunky-z.github.io/2021/08/10/Linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/">Linux 操作系统 - 进程间通信</a>，<a href="https://github.com/Dunky-Z/learning-linux/tree/main/IPC/SharedMemory">代码同步在这里</a>。</p>
<p>本文通过实例介绍通过共享内存实现进程间通信。</p>
<h2 id="简介">简介</h2>
<p>信号就像实际生产过程中的应急预案，发生了某个异常就会启动特定的应急预案，为了响应各类异常情况，所以就定义了很多个信号，信号的名称是在头文件<code>signal.h</code>中定义的，信号都以<code>SIG</code>开头，常用的信号并不多，常用的信号如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">SIGALRM     #时钟定时信号, 计算的是实际的时间或时钟时间
</span></span><span class="line"><span class="cl">SIGHUP      #终端的挂断或进程死亡
</span></span><span class="line"><span class="cl">SIGINT      #来自键盘的中断信号
</span></span><span class="line"><span class="cl">SIGKILL     #用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。
</span></span><span class="line"><span class="cl">SIGPIPE     #管道破裂
</span></span><span class="line"><span class="cl">SIGTERM     #程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理
</span></span><span class="line"><span class="cl">SIGUSR1,SIGUSR2     #留给用户使用
</span></span></code></pre></div><h2 id="实例">实例</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;signal.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">signalHandler</span><span class="p">(</span><span class="kt">int</span> <span class="n">sig</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;</span><span class="se">\n</span><span class="s">Ops! - I got signal %d</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">sig</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 恢复终端中断信号 SIGINT 的默认行为
</span></span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">signal</span><span class="p">(</span><span class="n">SIGINT</span><span class="p">,</span> <span class="n">SIG_DFL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 改变终端中断信号 SIGINT 的默认行为，使之执行 ouch 函数
</span></span></span><span class="line"><span class="cl">    <span class="c1">// 而不是终止程序的执行
</span></span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">signal</span><span class="p">(</span><span class="n">SIGINT</span><span class="p">,</span> <span class="n">signalHandler</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;Hello World!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>我们可以用<code>signal()</code>函数处理指定的信号，主要通过忽略和恢复其默认行为来工作。signal() 函数的原型如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="nf">signal</span><span class="p">(</span><span class="kt">int</span> <span class="n">sig</span><span class="p">,</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">func</span><span class="p">)(</span><span class="kt">int</span><span class="p">)))(</span><span class="kt">int</span><span class="p">);</span>
</span></span></code></pre></div><p>这是一个相当复杂的声明，耐心点看可以知道 signal 是一个带有<code>sig</code>和<code>func</code>两个参数的函数，<code>func</code>是一个类型为<code>void (*)(int)</code>的函数指针。该函数返回一个与<code>func</code>相同类型的指针，指向先前指定信号处理函数的函数指针。准备捕获的信号的参数由<code>sig</code>给出，接收到的指定信号后要调用的函数由参数<code>func</code>给出。其实这个函数的使用是相当简单的，通过下面的例子就可以知道。注意信号处理函数的原型必须为<code>void func（int）</code>，或者是下面的特殊值：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">SIG_IGN : 忽略信号
</span></span><span class="line"><span class="cl">SIG_DFL : 恢复信号的默认行为
</span></span></code></pre></div><p>我们程序的目的是想要捕获键盘输入<code>Ctrl+C</code>，这个中断。通过表里可以查到，我们使用<code>SIGINT</code>这个信号，当我们的程序出现<code>SIGINT</code>信号时，让程序接下来干啥呢？正常情况下，我们的<code>Ctrl+C</code>会中断当前运行的程序，但是现在我们做了一些更改，更改的内容在我们自己编写的<code>signalHandler</code>中。我们让程序输出一行字符串加上信号值。然后再把信号的行为恢复原样。此时我们运行程序可以得到如下</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210811143147.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210811143147.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>在我们第一输入<code>Ctrl+C</code>时，程序没有中断，而是调用了<code>signalHanlder</code>函数，因为我们更改了信号的行为。但是第二次输入<code>Ctrl+C</code>时，程序中断了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>进程间通信（IPC）之共享内存 (SharedMemory)</title>
      <link>https://lifeislife.cn/posts/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1ipc%E4%B9%8B%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98sharedmemory/</link>
      <pubDate>Tue, 10 Aug 2021 17:41:26 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1ipc%E4%B9%8B%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98sharedmemory/</guid>
      <description>&lt;p&gt;关于进程间通信的概述可以查看&lt;a href=&#34;https://dunky-z.github.io/2021/08/10/Linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/&#34;&gt;Linux 操作系统 - 进程间通信&lt;/a&gt;，&lt;a href=&#34;https://github.com/Dunky-Z/learning-linux/tree/main/IPC/SharedMemory&#34;&gt;代码同步在这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;本文通过实例介绍通过共享内存实现进程间通信。&lt;/p&gt;
&lt;h2 id=&#34;shmget得到一个共享内存标识符或创建一个共享内存对象&#34;&gt;shmget(得到一个共享内存标识符或创建一个共享内存对象)&lt;/h2&gt;
&lt;p&gt;我们可以通过&lt;code&gt;shmget&lt;/code&gt;函数创建或打开共享内存，通过函数签名&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//key_t key:  唯一定位一个共享内存对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//size_t size: 共享内存大小
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//int flag: 如果是 IPC_CREAT 表示创建新的共享内存空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shmget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flag&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;第一个参数是共享内存的唯一标识，是需要我们指定的。那么如何指定&lt;code&gt;key&lt;/code&gt;呢？如何保证唯一性呢？我们可以指定一个文件，&lt;code&gt;ftok&lt;/code&gt;会根据这个文件的 &lt;code&gt;inode&lt;/code&gt;，生成一个近乎唯一的 &lt;code&gt;key&lt;/code&gt;。只要在这个消息队列的生命周期内，这个文件不要被删除就可以了。只要不删除，无论什么时刻，再调用 &lt;code&gt;ftok&lt;/code&gt;，也会得到同样的&lt;code&gt;key&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;第二个参数是申请的空间大小，我们就申请 1024B。&lt;/li&gt;
&lt;li&gt;第三个参数是权限标识，&lt;code&gt;IPC_CREAT&lt;/code&gt;表示创建共享内存，&lt;code&gt;0644&lt;/code&gt;表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据，同时其他用户创建的进程只能读取共享内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;shmat把共享内存区对象映射到调用进程的地址空间&#34;&gt;shmat(把共享内存区对象映射到调用进程的地址空间)&lt;/h2&gt;
&lt;p&gt;第一次创建完共享内存时，它还不能被任何进程访问，&lt;code&gt;shmat()&lt;/code&gt;函数的作用就是用来启动对该共享内存的访问，并把共享内存连接到当前进程的地址空间。它的签名如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;shmat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shm_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shm_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmflg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;第一个参数就是上文产生的唯一标识。&lt;/li&gt;
&lt;li&gt;第二个参数，&lt;code&gt;shm_addr&lt;/code&gt;指定共享内存连接到当前进程中的地址位置，通常为空，表示让系统来选择共享内存的地址。&lt;/li&gt;
&lt;li&gt;第三个参数，&lt;code&gt;shm_flg&lt;/code&gt;是一组标志位，通常为 0。
调用成功时返回一个指向共享内存第一个字节的指针，如果调用失败返回-1.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;(void *) - 1&lt;/code&gt;把&lt;code&gt;-1&lt;/code&gt;转换为指针&lt;code&gt;0xFFFFFFFF&lt;/code&gt;，有时也会用到&lt;code&gt;(void*)0&lt;/code&gt;，表示一个空指针。&lt;/p&gt;
&lt;h2 id=&#34;shmdt断开共享内存连接&#34;&gt;shmdt(断开共享内存连接)&lt;/h2&gt;
&lt;p&gt;与 shmat 函数相反，是用来断开与共享内存附加点的地址，禁止本进程访问此片共享内存&lt;/p&gt;
&lt;p&gt;函数签名如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shmdt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmaddr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;参数一&lt;code&gt;shmaddr&lt;/code&gt;为连接共享内存的起始地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要注意的是，本函数调用并不删除所指定的共享内存区，而只是将先前用 shmat 函数连接（attach）好的共享内存脱离（detach）目前的进程。删除共享内存就需要下面的这个函数。&lt;/p&gt;
&lt;h2 id=&#34;shmctl共享内存管理&#34;&gt;shmctl(共享内存管理)&lt;/h2&gt;
&lt;p&gt;完成对共享内存的控制，包括改变状态，删除共享内存等。&lt;/p&gt;
&lt;p&gt;函数签名如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shmctl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmid_ds&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;shmid&lt;/code&gt;共享内存唯一标识符&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cmd&lt;/code&gt;执行的操作，包括如下
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IPC_STAT&lt;/code&gt;：得到共享内存的状态，把共享内存的&lt;code&gt;shmid_ds&lt;/code&gt;结构复制到&lt;code&gt;buf&lt;/code&gt;中&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPC_SET&lt;/code&gt;：改变共享内存的状态，把&lt;code&gt;buf&lt;/code&gt;所指的&lt;code&gt;shmid_ds&lt;/code&gt;结构中的&lt;code&gt;uid&lt;/code&gt;、&lt;code&gt;gid&lt;/code&gt;、&lt;code&gt;mode&lt;/code&gt;复制到共享内存的&lt;code&gt;shmid_ds&lt;/code&gt;结构内&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IPC_RMID&lt;/code&gt;：删除这片共享内存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;buf&lt;/code&gt;共享内存管理结构体。具体说明参见共享内存内核结构定义部分&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//server.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/ipc.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/shm.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmkey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;shmkey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ftok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;./client.c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 创建或打开内存共享区域
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shmget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmkey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0666&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;IPC_CREAT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;shmget error!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//将共享内存映射到当前进程的地址中，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//之后直接对进程中的地址 addr 操作就是对共享内存操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;shmptr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;shmat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmptr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;shmat error!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 把用户的输入存到共享内存区域中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;input:&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;scanf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//client.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/ipc.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;sys/shm.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;key_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmkey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;shmkey&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ftok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;./client.c&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 创建或打开内存共享区域
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;shmget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmkey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;0666&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;IPC_CREAT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;shmget error!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//将共享内存映射到当前进程的地址中，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;//之后直接对进程中的地址 addr 操作就是对共享内存操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;shmptr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;shmat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shmptr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;fprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stderr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;shmat error!&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 每隔 3 秒从共享内存中取一次数据并打印到控制台
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;string:%s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shmptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;sleep&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在两个终端分别运行&lt;code&gt;client&lt;/code&gt;和&lt;code&gt;server&lt;/code&gt;，&lt;code&gt;client&lt;/code&gt;会每三秒在终端打印出&lt;code&gt;server&lt;/code&gt;输入的内容。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810205816.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810205816.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810205830.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810205830.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;如何手动删除共享内存&#34;&gt;如何手动删除共享内存？&lt;/h3&gt;
&lt;p&gt;列出所有的共享内存段：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ipcs -m
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;------------ 共享内存段 --------------
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;键        shmid      拥有者  权限     字节     连接数  状态      
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 2          dominic    600        16384      1          目标       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 753668     dominic    606        10089696   2          目标       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 622597     dominic    600        4194304    2          目标       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 753670     dominic    606        10089696   2          目标       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 688135     dominic    600        899976     2          目标       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 8          dominic    600        524288     2          目标       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 9          dominic    600        524288     2          目标       
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x00000000 753674     dominic    600        7127040    2          目标 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x0000006f 720918     dominic    666        1024        0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们发现最后一个键值为&lt;code&gt;0x0000006f = 111&lt;/code&gt;的共享内存段，就是我们创建的共享内存段。
删除指定共享内存段：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; ipcrm -m 720918  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 或者 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; ipcrm -M 0x0000006f  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;信号量和消息队列的操作，命令类似，只是参数不同。
查看命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ipcs [-m|-q|-s]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt; 输出有关共享内存 (shared memory) 的信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt; 输出有关信息队列 (message queue) 的信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt; 输出有关“信号量”(semaphore) 的信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;删除命令&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-M&lt;/code&gt;用 shmkey 删除共享内存&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt;用 shmid 删除共享内存&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-Q&lt;/code&gt;用 msgkey 删除消息队列&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt;用 msgid 删除消息队列&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-S&lt;/code&gt;用 semkey 删除信号量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;/code&gt;用 semid 删除信号量&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;超过共享内存的大小限制&#34;&gt;超过共享内存的大小限制&lt;/h2&gt;
&lt;p&gt;共享内存的总体大小是有限制的，这个大小通过 SHMMAX 参数来定义（以字节为单位），您可以通过执行以下命令来确定 SHMMAX 的值：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /proc/sys/kernel/shmmax
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果机器上创建的共享内存的总共大小超出了这个限制，在程序中使用标准错误&lt;code&gt;perror&lt;/code&gt;可能会出现以下的信息：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;unable to attach to shared memory
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;1、设置 SHMMAX&lt;/p&gt;
&lt;p&gt;　　SHMMAX 的默认值是 &lt;code&gt;32MB&lt;/code&gt; 。一般使用下列方法之一种将 SHMMAX 参数设为 &lt;code&gt;2GB&lt;/code&gt; ：
通过直接更改 &lt;code&gt;/proc&lt;/code&gt; 文件系统，你不需重新启动机器就可以改变 SHMMAX 的默认设置。我使用的方法是将以下命令放入 &lt;code&gt;/&amp;gt;etc/rc.local&lt;/code&gt; 启动文件中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;2147483648&amp;#34; &amp;gt; /proc/sys/kernel/shmmax
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;您还可以使用 &lt;code&gt;sysctl&lt;/code&gt; 命令来更改 SHMMAX 的值：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sysctl -w kernel.shmmax=2147483648
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后，通过将该内核参数插入到&lt;code&gt;/etc/sysctl.conf&lt;/code&gt; 启动文件中，您可以使这种更改永久有效：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;echo &amp;#34;kernel.shmmax=2147483648&amp;#34; &amp;gt;&amp;gt; /etc/sysctl.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;2、设置 SHMMNI&lt;/p&gt;
&lt;p&gt;我们现在来看 SHMMNI 参数。这个内核参数用于设置系统范围内共享内存段的最大数量。该参数的默认值是 &lt;code&gt;4096&lt;/code&gt; 。这一数值已经足够，通常不需要更改。您可以通过执行以下命令来确定 SHMMNI 的值：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /proc/sys/kernel/shmmni
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;3、设置 SHMALL&lt;/p&gt;
&lt;p&gt;最后，我们来看 SHMALL 共享内存内核参数。该参数控制着系统一次可以使用的共享内存总量（以页为单位）。简言之，该参数的值始终应该至少为：&lt;code&gt;ceil(SHMMAX/PAGE_SIZE)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;SHMALL 的默认大小为 &lt;code&gt;2097152&lt;/code&gt; ，可以使用以下命令进行查询：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat /proc/sys/kernel/shmall
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;　　SHMALL 的默认设置对于我们来说应该足够使用。注意：在 i386 平台上 Red Hat Linux 的 页面大小 为 &lt;code&gt;4096&lt;/code&gt; 字节。但是，您可以使用 &lt;code&gt;bigpages&lt;/code&gt; ，它支持配置更大的内存页面尺寸。&lt;/p&gt;
&lt;h2 id=&#34;多次进行-shmat-操作会出现什么问题&#34;&gt;多次进行 shmat 操作会出现什么问题&lt;/h2&gt;
&lt;p&gt;一个进程是可以对同一个共享内存多次 shmat 进行挂载的，物理内存是指向同一块，如果 shmaddr 为 NULL，则每次返回的线性地址空间都不同。而且指向这块共享内存的引用计数会增加。也就是进程多块线性空间会指向同一块物理地址。这样，如果之前挂载过这块共享内存的进程的线性地址没有被&lt;code&gt;shmdt&lt;/code&gt;掉，即申请的线性地址都没有释放，就会一直消耗进程的虚拟内存空间，很有可能会最后导致进程线性空间被使用完而导致下次 shmat 或者其他操作失败。&lt;/p&gt;
&lt;h2 id=&#34;shmget-创建共享内存当-key-相同时什么情况下会出错&#34;&gt;shmget 创建共享内存，当 key 相同时，什么情况下会出错？&lt;/h2&gt;
&lt;p&gt;当创建一个新的共享内存区时，size 的值必须大于 0；如果是访问一个已经存在的内存共享区，则置 size 为 0。&lt;/p&gt;
&lt;p&gt;已经创建的共享内存的大小是可以调整的，但是已经创建的共享内存的大小只能调小，不能调大&lt;/p&gt;
&lt;p&gt;当多个进程都能创建共享内存的时候，如果 key 出现相同的情况，并且一个进程需要创建的共享内存的大小要比另外一个进程要创建的共享内存小，共享内存大的进程先创建共享内存，共享内存小的进程后创建共享内存，小共享内存的进程就会获取到大的共享内存进程的共享内存，并修改其共享内存的大小和内容，从而可能导致大的共享内存进程崩溃。&lt;/p&gt;
&lt;h2 id=&#34;ftok-是否一定会产生唯一的-key-值&#34;&gt;ftok 是否一定会产生唯一的 key 值？&lt;/h2&gt;
&lt;p&gt;ftok 原型如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;key_t ftok(char * pathname, int proj_id)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;pathname&lt;/code&gt;就时你指定的文件名，&lt;code&gt;proj_id&lt;/code&gt;是子序号。在一般的 UNIX 实现中，是将文件的索引节点号取出，前面加上子序号得到&lt;code&gt;key_t&lt;/code&gt;的返回值。如指定文件的索引节点号为 65538，换算成 16 进制为&lt;code&gt;0×010002&lt;/code&gt;，而你指定的&lt;code&gt;proj_id&lt;/code&gt;值为&lt;code&gt;38&lt;/code&gt;，换算成 16 进制为&lt;code&gt;0×26&lt;/code&gt;，则最后的&lt;code&gt;key_t&lt;/code&gt;返回值为&lt;code&gt;0×26010002&lt;/code&gt;。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>关于进程间通信的概述可以查看<a href="https://dunky-z.github.io/2021/08/10/Linux%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F-%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/">Linux 操作系统 - 进程间通信</a>，<a href="https://github.com/Dunky-Z/learning-linux/tree/main/IPC/SharedMemory">代码同步在这里</a>。</p>
<p>本文通过实例介绍通过共享内存实现进程间通信。</p>
<h2 id="shmget得到一个共享内存标识符或创建一个共享内存对象">shmget(得到一个共享内存标识符或创建一个共享内存对象)</h2>
<p>我们可以通过<code>shmget</code>函数创建或打开共享内存，通过函数签名</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//key_t key:  唯一定位一个共享内存对象
</span></span></span><span class="line"><span class="cl"><span class="c1">//size_t size: 共享内存大小
</span></span></span><span class="line"><span class="cl"><span class="c1">//int flag: 如果是 IPC_CREAT 表示创建新的共享内存空间
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">shmget</span><span class="p">(</span><span class="kt">key_t</span> <span class="n">key</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">size</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flag</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li>第一个参数是共享内存的唯一标识，是需要我们指定的。那么如何指定<code>key</code>呢？如何保证唯一性呢？我们可以指定一个文件，<code>ftok</code>会根据这个文件的 <code>inode</code>，生成一个近乎唯一的 <code>key</code>。只要在这个消息队列的生命周期内，这个文件不要被删除就可以了。只要不删除，无论什么时刻，再调用 <code>ftok</code>，也会得到同样的<code>key</code>。</li>
<li>第二个参数是申请的空间大小，我们就申请 1024B。</li>
<li>第三个参数是权限标识，<code>IPC_CREAT</code>表示创建共享内存，<code>0644</code>表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据，同时其他用户创建的进程只能读取共享内存。</li>
</ul>
<h2 id="shmat把共享内存区对象映射到调用进程的地址空间">shmat(把共享内存区对象映射到调用进程的地址空间)</h2>
<p>第一次创建完共享内存时，它还不能被任何进程访问，<code>shmat()</code>函数的作用就是用来启动对该共享内存的访问，并把共享内存连接到当前进程的地址空间。它的签名如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">void</span> <span class="o">*</span><span class="nf">shmat</span><span class="p">(</span><span class="kt">int</span> <span class="n">shm_id</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">shm_addr</span><span class="p">,</span> <span class="kt">int</span> <span class="n">shmflg</span><span class="p">);</span>
</span></span></code></pre></div><ul>
<li>第一个参数就是上文产生的唯一标识。</li>
<li>第二个参数，<code>shm_addr</code>指定共享内存连接到当前进程中的地址位置，通常为空，表示让系统来选择共享内存的地址。</li>
<li>第三个参数，<code>shm_flg</code>是一组标志位，通常为 0。
调用成功时返回一个指向共享内存第一个字节的指针，如果调用失败返回-1.</li>
</ul>
<p><code>(void *) - 1</code>把<code>-1</code>转换为指针<code>0xFFFFFFFF</code>，有时也会用到<code>(void*)0</code>，表示一个空指针。</p>
<h2 id="shmdt断开共享内存连接">shmdt(断开共享内存连接)</h2>
<p>与 shmat 函数相反，是用来断开与共享内存附加点的地址，禁止本进程访问此片共享内存</p>
<p>函数签名如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">shmdt</span><span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">shmaddr</span><span class="p">)</span>
</span></span></code></pre></div><ul>
<li>参数一<code>shmaddr</code>为连接共享内存的起始地址。</li>
</ul>
<p>需要注意的是，本函数调用并不删除所指定的共享内存区，而只是将先前用 shmat 函数连接（attach）好的共享内存脱离（detach）目前的进程。删除共享内存就需要下面的这个函数。</p>
<h2 id="shmctl共享内存管理">shmctl(共享内存管理)</h2>
<p>完成对共享内存的控制，包括改变状态，删除共享内存等。</p>
<p>函数签名如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">shmctl</span><span class="p">(</span><span class="kt">int</span> <span class="n">shmid</span><span class="p">,</span> <span class="kt">int</span> <span class="n">cmd</span><span class="p">,</span> <span class="k">struct</span> <span class="n">shmid_ds</span> <span class="o">*</span><span class="n">buf</span><span class="p">)</span>
</span></span></code></pre></div><ul>
<li><code>shmid</code>共享内存唯一标识符</li>
<li><code>cmd</code>执行的操作，包括如下
<ul>
<li><code>IPC_STAT</code>：得到共享内存的状态，把共享内存的<code>shmid_ds</code>结构复制到<code>buf</code>中</li>
<li><code>IPC_SET</code>：改变共享内存的状态，把<code>buf</code>所指的<code>shmid_ds</code>结构中的<code>uid</code>、<code>gid</code>、<code>mode</code>复制到共享内存的<code>shmid_ds</code>结构内</li>
<li><code>IPC_RMID</code>：删除这片共享内存</li>
</ul>
</li>
<li><code>buf</code>共享内存管理结构体。具体说明参见共享内存内核结构定义部分</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//server.c
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/types.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/ipc.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/shm.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">shmid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">key_t</span> <span class="n">shmkey</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="o">*</span><span class="n">shmptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">shmkey</span> <span class="o">=</span> <span class="nf">ftok</span><span class="p">(</span><span class="s">&#34;./client.c&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 创建或打开内存共享区域
</span></span></span><span class="line"><span class="cl">    <span class="n">shmid</span> <span class="o">=</span> <span class="nf">shmget</span><span class="p">(</span><span class="n">shmkey</span><span class="p">,</span> <span class="mi">1024</span><span class="p">,</span> <span class="mo">0666</span> <span class="o">|</span> <span class="n">IPC_CREAT</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">shmid</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;shmget error!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">//将共享内存映射到当前进程的地址中，
</span></span></span><span class="line"><span class="cl">    <span class="c1">//之后直接对进程中的地址 addr 操作就是对共享内存操作
</span></span></span><span class="line"><span class="cl">    <span class="n">shmptr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="nf">shmat</span><span class="p">(</span><span class="n">shmid</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">shmptr</span> <span class="o">==</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;shmat error!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 把用户的输入存到共享内存区域中
</span></span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;input:&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">scanf</span><span class="p">(</span><span class="s">&#34;%s&#34;</span><span class="p">,</span> <span class="n">shmptr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//client.c
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/types.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/ipc.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/shm.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="n">shmid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">char</span> <span class="o">*</span><span class="n">shmptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">key_t</span> <span class="n">shmkey</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">shmkey</span> <span class="o">=</span> <span class="nf">ftok</span><span class="p">(</span><span class="s">&#34;./client.c&#34;</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 创建或打开内存共享区域
</span></span></span><span class="line"><span class="cl">    <span class="n">shmid</span> <span class="o">=</span> <span class="nf">shmget</span><span class="p">(</span><span class="n">shmkey</span><span class="p">,</span> <span class="mi">1024</span><span class="p">,</span> <span class="mo">0666</span> <span class="o">|</span> <span class="n">IPC_CREAT</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">shmid</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;shmget error!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">//将共享内存映射到当前进程的地址中，
</span></span></span><span class="line"><span class="cl">    <span class="c1">//之后直接对进程中的地址 addr 操作就是对共享内存操作
</span></span></span><span class="line"><span class="cl">    <span class="n">shmptr</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="nf">shmat</span><span class="p">(</span><span class="n">shmid</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">shmptr</span> <span class="o">==</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&#34;shmat error!</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 每隔 3 秒从共享内存中取一次数据并打印到控制台
</span></span></span><span class="line"><span class="cl">        <span class="nf">printf</span><span class="p">(</span><span class="s">&#34;string:%s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">shmptr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="nf">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在两个终端分别运行<code>client</code>和<code>server</code>，<code>client</code>会每三秒在终端打印出<code>server</code>输入的内容。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810205816.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810205816.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810205830.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210810205830.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="如何手动删除共享内存">如何手动删除共享内存？</h3>
<p>列出所有的共享内存段：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ipcs -m
</span></span><span class="line"><span class="cl">------------ 共享内存段 --------------
</span></span><span class="line"><span class="cl">键        shmid      拥有者  权限     字节     连接数  状态      
</span></span><span class="line"><span class="cl">0x00000000 2          dominic    600        16384      1          目标       
</span></span><span class="line"><span class="cl">0x00000000 753668     dominic    606        10089696   2          目标       
</span></span><span class="line"><span class="cl">0x00000000 622597     dominic    600        4194304    2          目标       
</span></span><span class="line"><span class="cl">0x00000000 753670     dominic    606        10089696   2          目标       
</span></span><span class="line"><span class="cl">0x00000000 688135     dominic    600        899976     2          目标       
</span></span><span class="line"><span class="cl">0x00000000 8          dominic    600        524288     2          目标       
</span></span><span class="line"><span class="cl">0x00000000 9          dominic    600        524288     2          目标       
</span></span><span class="line"><span class="cl">0x00000000 753674     dominic    600        7127040    2          目标 
</span></span><span class="line"><span class="cl">0x0000006f 720918     dominic    666        1024        0
</span></span></code></pre></div><p>我们发现最后一个键值为<code>0x0000006f = 111</code>的共享内存段，就是我们创建的共享内存段。
删除指定共享内存段：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"> ipcrm -m 720918  
</span></span><span class="line"><span class="cl"> 或者 
</span></span><span class="line"><span class="cl"> ipcrm -M 0x0000006f  
</span></span></code></pre></div><p>信号量和消息队列的操作，命令类似，只是参数不同。
查看命令：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ipcs [-m|-q|-s]
</span></span></code></pre></div><ul>
<li><code>-m</code> 输出有关共享内存 (shared memory) 的信息</li>
<li><code>-q</code> 输出有关信息队列 (message queue) 的信息</li>
<li><code>-s</code> 输出有关“信号量”(semaphore) 的信息</li>
</ul>
<p>删除命令</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ]
</span></span></code></pre></div><ul>
<li><code>-M</code>用 shmkey 删除共享内存</li>
<li><code>-m</code>用 shmid 删除共享内存</li>
<li><code>-Q</code>用 msgkey 删除消息队列</li>
<li><code>-q</code>用 msgid 删除消息队列</li>
<li><code>-S</code>用 semkey 删除信号量</li>
<li><code>-s</code>用 semid 删除信号量</li>
</ul>
<h2 id="超过共享内存的大小限制">超过共享内存的大小限制</h2>
<p>共享内存的总体大小是有限制的，这个大小通过 SHMMAX 参数来定义（以字节为单位），您可以通过执行以下命令来确定 SHMMAX 的值：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">cat /proc/sys/kernel/shmmax
</span></span></code></pre></div><p>如果机器上创建的共享内存的总共大小超出了这个限制，在程序中使用标准错误<code>perror</code>可能会出现以下的信息：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">unable to attach to shared memory
</span></span></code></pre></div><p>1、设置 SHMMAX</p>
<p>　　SHMMAX 的默认值是 <code>32MB</code> 。一般使用下列方法之一种将 SHMMAX 参数设为 <code>2GB</code> ：
通过直接更改 <code>/proc</code> 文件系统，你不需重新启动机器就可以改变 SHMMAX 的默认设置。我使用的方法是将以下命令放入 <code>/&gt;etc/rc.local</code> 启动文件中：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">echo &#34;2147483648&#34; &gt; /proc/sys/kernel/shmmax
</span></span></code></pre></div><p>您还可以使用 <code>sysctl</code> 命令来更改 SHMMAX 的值：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sysctl -w kernel.shmmax=2147483648
</span></span></code></pre></div><p>最后，通过将该内核参数插入到<code>/etc/sysctl.conf</code> 启动文件中，您可以使这种更改永久有效：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">echo &#34;kernel.shmmax=2147483648&#34; &gt;&gt; /etc/sysctl.conf
</span></span></code></pre></div><p>2、设置 SHMMNI</p>
<p>我们现在来看 SHMMNI 参数。这个内核参数用于设置系统范围内共享内存段的最大数量。该参数的默认值是 <code>4096</code> 。这一数值已经足够，通常不需要更改。您可以通过执行以下命令来确定 SHMMNI 的值：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">cat /proc/sys/kernel/shmmni
</span></span></code></pre></div><p>3、设置 SHMALL</p>
<p>最后，我们来看 SHMALL 共享内存内核参数。该参数控制着系统一次可以使用的共享内存总量（以页为单位）。简言之，该参数的值始终应该至少为：<code>ceil(SHMMAX/PAGE_SIZE)</code></p>
<p>SHMALL 的默认大小为 <code>2097152</code> ，可以使用以下命令进行查询：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">cat /proc/sys/kernel/shmall
</span></span></code></pre></div><p>　　SHMALL 的默认设置对于我们来说应该足够使用。注意：在 i386 平台上 Red Hat Linux 的 页面大小 为 <code>4096</code> 字节。但是，您可以使用 <code>bigpages</code> ，它支持配置更大的内存页面尺寸。</p>
<h2 id="多次进行-shmat-操作会出现什么问题">多次进行 shmat 操作会出现什么问题</h2>
<p>一个进程是可以对同一个共享内存多次 shmat 进行挂载的，物理内存是指向同一块，如果 shmaddr 为 NULL，则每次返回的线性地址空间都不同。而且指向这块共享内存的引用计数会增加。也就是进程多块线性空间会指向同一块物理地址。这样，如果之前挂载过这块共享内存的进程的线性地址没有被<code>shmdt</code>掉，即申请的线性地址都没有释放，就会一直消耗进程的虚拟内存空间，很有可能会最后导致进程线性空间被使用完而导致下次 shmat 或者其他操作失败。</p>
<h2 id="shmget-创建共享内存当-key-相同时什么情况下会出错">shmget 创建共享内存，当 key 相同时，什么情况下会出错？</h2>
<p>当创建一个新的共享内存区时，size 的值必须大于 0；如果是访问一个已经存在的内存共享区，则置 size 为 0。</p>
<p>已经创建的共享内存的大小是可以调整的，但是已经创建的共享内存的大小只能调小，不能调大</p>
<p>当多个进程都能创建共享内存的时候，如果 key 出现相同的情况，并且一个进程需要创建的共享内存的大小要比另外一个进程要创建的共享内存小，共享内存大的进程先创建共享内存，共享内存小的进程后创建共享内存，小共享内存的进程就会获取到大的共享内存进程的共享内存，并修改其共享内存的大小和内容，从而可能导致大的共享内存进程崩溃。</p>
<h2 id="ftok-是否一定会产生唯一的-key-值">ftok 是否一定会产生唯一的 key 值？</h2>
<p>ftok 原型如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">key_t ftok(char * pathname, int proj_id)
</span></span></code></pre></div><p><code>pathname</code>就时你指定的文件名，<code>proj_id</code>是子序号。在一般的 UNIX 实现中，是将文件的索引节点号取出，前面加上子序号得到<code>key_t</code>的返回值。如指定文件的索引节点号为 65538，换算成 16 进制为<code>0×010002</code>，而你指定的<code>proj_id</code>值为<code>38</code>，换算成 16 进制为<code>0×26</code>，则最后的<code>key_t</code>返回值为<code>0×26010002</code>。</p>
]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-ar 多文件归档为一个文件</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ar%E5%A4%9A%E6%96%87%E4%BB%B6%E5%BD%92%E6%A1%A3%E4%B8%BA%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6/</link>
      <pubDate>Tue, 10 Aug 2021 11:33:49 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ar%E5%A4%9A%E6%96%87%E4%BB%B6%E5%BD%92%E6%A1%A3%E4%B8%BA%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6/</guid>
      <description>&lt;p&gt;现在我们有&lt;code&gt;solution.c&lt;/code&gt;,&lt;code&gt;solution.h&lt;/code&gt;两个文件，他们实现了某一个功能，自成一个模块。在其他项目中也可复用。我们就可以把它做成库文件。&lt;code&gt;ar&lt;/code&gt;命令就可以将锁哥文件整合成一个库文件，也可以从一个库中单独提取出某一个文件。&lt;/p&gt;
&lt;h2 id=&#34;commands&#34;&gt;Commands&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-d 　删除备存文件中的成员文件。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-m 　变更成员文件在备存文件中的次序。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-p 　显示备存文件中的成员文件内容。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-q 　将文件附加在备存文件末端。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-r 　将文件插入备存文件中。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-t 　显示备存文件中所包含的文件。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-x 　自备存文件中取出成员文件。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;
&lt;h3 id=&#34;打包文件&#34;&gt;打包文件&lt;/h3&gt;
&lt;p&gt;将&lt;code&gt;solution.c solution.h&lt;/code&gt;两个文件打包成&lt;code&gt;solution.bak&lt;/code&gt;，并显示详细信息&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ar rv solution.bak solution.c solution.h
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ar: 正在创建 solution.bak
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a - solution.c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a - solution.h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;显示打包文件内容&#34;&gt;显示打包文件内容&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ar t solution.bak 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;solution.c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;solution.h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>现在我们有<code>solution.c</code>,<code>solution.h</code>两个文件，他们实现了某一个功能，自成一个模块。在其他项目中也可复用。我们就可以把它做成库文件。<code>ar</code>命令就可以将锁哥文件整合成一个库文件，也可以从一个库中单独提取出某一个文件。</p>
<h2 id="commands">Commands</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">-d 　删除备存文件中的成员文件。
</span></span><span class="line"><span class="cl">-m 　变更成员文件在备存文件中的次序。
</span></span><span class="line"><span class="cl">-p 　显示备存文件中的成员文件内容。
</span></span><span class="line"><span class="cl">-q 　将文件附加在备存文件末端。
</span></span><span class="line"><span class="cl">-r 　将文件插入备存文件中。
</span></span><span class="line"><span class="cl">-t 　显示备存文件中所包含的文件。
</span></span><span class="line"><span class="cl">-x 　自备存文件中取出成员文件。
</span></span></code></pre></div><h2 id="examples">Examples</h2>
<h3 id="打包文件">打包文件</h3>
<p>将<code>solution.c solution.h</code>两个文件打包成<code>solution.bak</code>，并显示详细信息</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ar rv solution.bak solution.c solution.h
</span></span><span class="line"><span class="cl">ar: 正在创建 solution.bak
</span></span><span class="line"><span class="cl">a - solution.c
</span></span><span class="line"><span class="cl">a - solution.h
</span></span></code></pre></div><h3 id="显示打包文件内容">显示打包文件内容</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ar t solution.bak 
</span></span><span class="line"><span class="cl">solution.c
</span></span><span class="line"><span class="cl">solution.h
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每日学命令-ps 显示进程状态</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E6%97%A5%E5%AD%A6%E5%91%BD%E4%BB%A4-ps%E6%98%BE%E7%A4%BA%E8%BF%9B%E7%A8%8B%E7%8A%B6%E6%80%81/</link>
      <pubDate>Mon, 09 Aug 2021 19:37:38 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E6%97%A5%E5%AD%A6%E5%91%BD%E4%BB%A4-ps%E6%98%BE%E7%A4%BA%E8%BF%9B%E7%A8%8B%E7%8A%B6%E6%80%81/</guid>
      <description>&lt;p&gt;&lt;code&gt;ps&lt;/code&gt;命令显示的信息类似于 Windows 的任务管理器。也是参数超级多的一个命令，所以就不列参数了，需要查看时直接搜索，这里列举一下实例。&lt;/p&gt;
&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;p&gt;显示当前执行的所有程序&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps -a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    PID TTY          TIME CMD
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;m&#34;&gt;879&lt;/span&gt; tty2     00:03:43 Xorg
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;m&#34;&gt;990&lt;/span&gt; tty2     00:00:00 gnome-session-b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;m&#34;&gt;2653&lt;/span&gt; pts/0    00:00:00 zsh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;m&#34;&gt;12365&lt;/span&gt; pts/0    00:00:00 ps
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;显示所有程序&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps -A
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    PID TTY          TIME CMD
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; ?        00:00:01 systemd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; ?        00:00:00 kthreadd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; ?        00:00:00 rcu_gp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; ?        00:00:00 rcu_par_gp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; ?        00:00:00 kworker/0:0H-kblockd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; ?        00:00:00 mm_percpu_wq
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt; ?        00:00:00 ksoftirqd/0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;m&#34;&gt;11&lt;/span&gt; ?        00:00:02 rcu_sched
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt; ?        00:00:00 migration/0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;m&#34;&gt;13&lt;/span&gt; ?        00:00:00 idle_inject/0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;m&#34;&gt;14&lt;/span&gt; ?        00:00:00 cpuhp/0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;m&#34;&gt;15&lt;/span&gt; ?        00:00:00 kdevtmpfs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;显示指定用户的信息&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps -u root
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;a&lt;/code&gt;显示现行终端机下的所有程序，包括其他用户的程序，&lt;code&gt;u&lt;/code&gt;以用户为主的格式来显示程序状况，&lt;code&gt;x&lt;/code&gt;显示所有程序，不以终端机来区分
&lt;code&gt;USER&lt;/code&gt;－运行该流程的用户。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;%CPU&lt;/code&gt;－进程 CPU 利用率。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;%MEM&lt;/code&gt;－进程驻留集大小占计算机物理内存的百分比。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;VSZ&lt;/code&gt;－KiB 中进程的虚拟内存大小。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RSS&lt;/code&gt;－进程正在使用的物理内存的大小。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;STAT&lt;/code&gt;－进程状态代码，可以是 Z（zombie），S（休眠），R（运行）..等等。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;START&lt;/code&gt;－命令启动的时间。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps aux              
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root           &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;  0.0  0.2 &lt;span class=&#34;m&#34;&gt;102084&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;11540&lt;/span&gt; ?        Ss   09:09   0:01 /sbin/init splash
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root           &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;  0.0  0.0      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ?        S    09:09   0:00 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;kthreadd&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root           &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;  0.0  0.0      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;     &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; ?        I&amp;lt;   09:09   0:00 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rcu_gp&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按 CPU 资源的使用量对进程进行排序：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps aux &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sort -nk &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;avahi        &lt;span class=&#34;m&#34;&gt;492&lt;/span&gt;  0.0  0.0   &lt;span class=&#34;m&#34;&gt;8536&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;3260&lt;/span&gt; ?        Ss   09:09   0:00 avahi-daemon: running &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;hanhan.local&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;avahi        &lt;span class=&#34;m&#34;&gt;552&lt;/span&gt;  0.0  0.0   &lt;span class=&#34;m&#34;&gt;8352&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;332&lt;/span&gt; ?        S    09:09   0:00 avahi-daemon: chroot helper
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;colord      &lt;span class=&#34;m&#34;&gt;1442&lt;/span&gt;  0.0  0.3 &lt;span class=&#34;m&#34;&gt;255144&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;14408&lt;/span&gt; ?        Ssl  09:09   0:00 /usr/libexec/colord
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic     &lt;span class=&#34;m&#34;&gt;1068&lt;/span&gt;  0.0  0.0  &lt;span class=&#34;m&#34;&gt;31244&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;364&lt;/span&gt; ?        S    09:09   0:00 /usr/bin/VBoxClient --clipboard
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic     &lt;span class=&#34;m&#34;&gt;1069&lt;/span&gt;  0.0  0.9 &lt;span class=&#34;m&#34;&gt;163512&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;39088&lt;/span&gt; ?        Sl   09:09   0:00 /usr/bin/VBoxClient --clipboard
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic     &lt;span class=&#34;m&#34;&gt;1080&lt;/span&gt;  0.0  0.0  &lt;span class=&#34;m&#34;&gt;31244&lt;/span&gt;   &lt;span class=&#34;m&#34;&gt;364&lt;/span&gt; ?        S    09:09   0:00 /usr/bin/VBoxClient --seamless
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 其中`sort`命令中`-n`为按数值进行排序，`-k  3` 表示以输出结果的第三列来进行排序，&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 从上一个实例中看到，第三列为CPU使用率`%CPU`。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 同理ps aux | sort -rnk 4 即按内存使用降序排序&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;显示前 5 名最耗 CPU 的进程&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps aux --sort&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;-pcpu &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; head -5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root         &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;  2.6  0.7  &lt;span class=&#34;m&#34;&gt;51396&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;7644&lt;/span&gt; ?        Ss   02:02   0:03 /usr/lib/systemd/systemd --switched-root --system --deserialize &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root      &lt;span class=&#34;m&#34;&gt;1249&lt;/span&gt;  2.6  3.0 &lt;span class=&#34;m&#34;&gt;355800&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;30896&lt;/span&gt; tty1     Rsl+ 02:02   0:02 /usr/bin/X -background none :0 vt01 -nolisten tcp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root       &lt;span class=&#34;m&#34;&gt;508&lt;/span&gt;  2.4  1.6 &lt;span class=&#34;m&#34;&gt;248488&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16776&lt;/span&gt; ?        Ss   02:02   0:03 /usr/bin/python /usr/sbin/firewalld --nofor
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面的命令会显示进程 id 为 3150 的进程的所有线程&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ ps -p &lt;span class=&#34;m&#34;&gt;3150&lt;/span&gt; -L
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p><code>ps</code>命令显示的信息类似于 Windows 的任务管理器。也是参数超级多的一个命令，所以就不列参数了，需要查看时直接搜索，这里列举一下实例。</p>
<h2 id="使用实例">使用实例</h2>
<p>显示当前执行的所有程序</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">➜  ~ ps -a
</span></span><span class="line"><span class="cl">    PID TTY          TIME CMD
</span></span><span class="line"><span class="cl">    <span class="m">879</span> tty2     00:03:43 Xorg
</span></span><span class="line"><span class="cl">    <span class="m">990</span> tty2     00:00:00 gnome-session-b
</span></span><span class="line"><span class="cl">   <span class="m">2653</span> pts/0    00:00:00 zsh
</span></span><span class="line"><span class="cl">  <span class="m">12365</span> pts/0    00:00:00 ps
</span></span></code></pre></div><p>显示所有程序</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">➜  ~ ps -A
</span></span><span class="line"><span class="cl">    PID TTY          TIME CMD
</span></span><span class="line"><span class="cl">      <span class="m">1</span> ?        00:00:01 systemd
</span></span><span class="line"><span class="cl">      <span class="m">2</span> ?        00:00:00 kthreadd
</span></span><span class="line"><span class="cl">      <span class="m">3</span> ?        00:00:00 rcu_gp
</span></span><span class="line"><span class="cl">      <span class="m">4</span> ?        00:00:00 rcu_par_gp
</span></span><span class="line"><span class="cl">      <span class="m">6</span> ?        00:00:00 kworker/0:0H-kblockd
</span></span><span class="line"><span class="cl">      <span class="m">9</span> ?        00:00:00 mm_percpu_wq
</span></span><span class="line"><span class="cl">     <span class="m">10</span> ?        00:00:00 ksoftirqd/0
</span></span><span class="line"><span class="cl">     <span class="m">11</span> ?        00:00:02 rcu_sched
</span></span><span class="line"><span class="cl">     <span class="m">12</span> ?        00:00:00 migration/0
</span></span><span class="line"><span class="cl">     <span class="m">13</span> ?        00:00:00 idle_inject/0
</span></span><span class="line"><span class="cl">     <span class="m">14</span> ?        00:00:00 cpuhp/0
</span></span><span class="line"><span class="cl">     <span class="m">15</span> ?        00:00:00 kdevtmpfs
</span></span><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">.
</span></span></code></pre></div><p>显示指定用户的信息</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">➜  ~ ps -u root
</span></span></code></pre></div><p><code>a</code>显示现行终端机下的所有程序，包括其他用户的程序，<code>u</code>以用户为主的格式来显示程序状况，<code>x</code>显示所有程序，不以终端机来区分
<code>USER</code>－运行该流程的用户。</p>
<p><code>%CPU</code>－进程 CPU 利用率。</p>
<p><code>%MEM</code>－进程驻留集大小占计算机物理内存的百分比。</p>
<p><code>VSZ</code>－KiB 中进程的虚拟内存大小。</p>
<p><code>RSS</code>－进程正在使用的物理内存的大小。</p>
<p><code>STAT</code>－进程状态代码，可以是 Z（zombie），S（休眠），R（运行）..等等。</p>
<p><code>START</code>－命令启动的时间。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">➜  ~ ps aux              
</span></span><span class="line"><span class="cl">USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
</span></span><span class="line"><span class="cl">root           <span class="m">1</span>  0.0  0.2 <span class="m">102084</span> <span class="m">11540</span> ?        Ss   09:09   0:01 /sbin/init splash
</span></span><span class="line"><span class="cl">root           <span class="m">2</span>  0.0  0.0      <span class="m">0</span>     <span class="m">0</span> ?        S    09:09   0:00 <span class="o">[</span>kthreadd<span class="o">]</span>
</span></span><span class="line"><span class="cl">root           <span class="m">3</span>  0.0  0.0      <span class="m">0</span>     <span class="m">0</span> ?        I&lt;   09:09   0:00 <span class="o">[</span>rcu_gp<span class="o">]</span>
</span></span></code></pre></div><p>按 CPU 资源的使用量对进程进行排序：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">➜  ~ ps aux <span class="p">|</span> sort -nk <span class="m">3</span>
</span></span><span class="line"><span class="cl">avahi        <span class="m">492</span>  0.0  0.0   <span class="m">8536</span>  <span class="m">3260</span> ?        Ss   09:09   0:00 avahi-daemon: running <span class="o">[</span>hanhan.local<span class="o">]</span>
</span></span><span class="line"><span class="cl">avahi        <span class="m">552</span>  0.0  0.0   <span class="m">8352</span>   <span class="m">332</span> ?        S    09:09   0:00 avahi-daemon: chroot helper
</span></span><span class="line"><span class="cl">colord      <span class="m">1442</span>  0.0  0.3 <span class="m">255144</span> <span class="m">14408</span> ?        Ssl  09:09   0:00 /usr/libexec/colord
</span></span><span class="line"><span class="cl">dominic     <span class="m">1068</span>  0.0  0.0  <span class="m">31244</span>   <span class="m">364</span> ?        S    09:09   0:00 /usr/bin/VBoxClient --clipboard
</span></span><span class="line"><span class="cl">dominic     <span class="m">1069</span>  0.0  0.9 <span class="m">163512</span> <span class="m">39088</span> ?        Sl   09:09   0:00 /usr/bin/VBoxClient --clipboard
</span></span><span class="line"><span class="cl">dominic     <span class="m">1080</span>  0.0  0.0  <span class="m">31244</span>   <span class="m">364</span> ?        S    09:09   0:00 /usr/bin/VBoxClient --seamless
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 其中`sort`命令中`-n`为按数值进行排序，`-k  3` 表示以输出结果的第三列来进行排序，</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 从上一个实例中看到，第三列为CPU使用率`%CPU`。</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 同理ps aux | sort -rnk 4 即按内存使用降序排序</span>
</span></span></code></pre></div><p>显示前 5 名最耗 CPU 的进程</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">➜  ~ ps aux --sort<span class="o">=</span>-pcpu <span class="p">|</span> head -5
</span></span><span class="line"><span class="cl">USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
</span></span><span class="line"><span class="cl">root         <span class="m">1</span>  2.6  0.7  <span class="m">51396</span>  <span class="m">7644</span> ?        Ss   02:02   0:03 /usr/lib/systemd/systemd --switched-root --system --deserialize <span class="m">23</span>
</span></span><span class="line"><span class="cl">root      <span class="m">1249</span>  2.6  3.0 <span class="m">355800</span> <span class="m">30896</span> tty1     Rsl+ 02:02   0:02 /usr/bin/X -background none :0 vt01 -nolisten tcp
</span></span><span class="line"><span class="cl">root       <span class="m">508</span>  2.4  1.6 <span class="m">248488</span> <span class="m">16776</span> ?        Ss   02:02   0:03 /usr/bin/python /usr/sbin/firewalld --nofor
</span></span></code></pre></div><p>下面的命令会显示进程 id 为 3150 的进程的所有线程</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">➜  ~ ps -p <span class="m">3150</span> -L
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-scp 远程拷贝文件</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-scp%E8%BF%9C%E7%A8%8B%E6%8B%B7%E8%B4%9D%E6%96%87%E4%BB%B6/</link>
      <pubDate>Fri, 06 Aug 2021 20:05:56 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-scp%E8%BF%9C%E7%A8%8B%E6%8B%B7%E8%B4%9D%E6%96%87%E4%BB%B6/</guid>
      <description>&lt;p&gt;看到同事要安装自己编译一天的库，本想传授一下“踩坑经验”，结果他用&lt;code&gt;scp&lt;/code&gt;命令直接从已经安装好的电脑里复制了一份。心里一万只 XXX 在奔腾。&lt;/p&gt;
&lt;p&gt;早知道先学学这个命令了。&lt;/p&gt;
&lt;h2 id=&#34;可选参数&#34;&gt;可选参数&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;参数&lt;/th&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;功能&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-1&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;强制 scp 命令使用协议 ssh1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-2&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;强制 scp 命令使用协议 ssh2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-4&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;强制 scp 命令使用协议 ssh2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-6&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;强制 scp 命令只使用 IPv6 寻址&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-B&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;使用批处理模式（传输过程中不询问传输口令或短语）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-C&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;允许压缩&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-p&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;保留原文件的修改时间，访问时间和访问权限。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-q&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;不显示传输进度条&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-r&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;递归复制整个目录&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-v&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;详细方式显示输出&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;-P&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;注意是大写的 P, port 是指定数据传输用到的端口号&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;p&gt;复制文件&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;scp local_file rmot_usr@rmot_ip:rmot_folder
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;scp /opt/soft/ root@192.168.120.204:/opt/soft/nginx-0.5.38.tar.gz 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>看到同事要安装自己编译一天的库，本想传授一下“踩坑经验”，结果他用<code>scp</code>命令直接从已经安装好的电脑里复制了一份。心里一万只 XXX 在奔腾。</p>
<p>早知道先学学这个命令了。</p>
<h2 id="可选参数">可选参数</h2>
<table>
	<thead>
			<tr>
					<th style="text-align: center">参数</th>
					<th style="text-align: center">功能</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: center">-1</td>
					<td style="text-align: center">强制 scp 命令使用协议 ssh1</td>
			</tr>
			<tr>
					<td style="text-align: center">-2</td>
					<td style="text-align: center">强制 scp 命令使用协议 ssh2</td>
			</tr>
			<tr>
					<td style="text-align: center">-4</td>
					<td style="text-align: center">强制 scp 命令使用协议 ssh2</td>
			</tr>
			<tr>
					<td style="text-align: center">-6</td>
					<td style="text-align: center">强制 scp 命令只使用 IPv6 寻址</td>
			</tr>
			<tr>
					<td style="text-align: center">-B</td>
					<td style="text-align: center">使用批处理模式（传输过程中不询问传输口令或短语）</td>
			</tr>
			<tr>
					<td style="text-align: center">-C</td>
					<td style="text-align: center">允许压缩</td>
			</tr>
			<tr>
					<td style="text-align: center">-p</td>
					<td style="text-align: center">保留原文件的修改时间，访问时间和访问权限。</td>
			</tr>
			<tr>
					<td style="text-align: center">-q</td>
					<td style="text-align: center">不显示传输进度条</td>
			</tr>
			<tr>
					<td style="text-align: center">-r</td>
					<td style="text-align: center">递归复制整个目录</td>
			</tr>
			<tr>
					<td style="text-align: center">-v</td>
					<td style="text-align: center">详细方式显示输出</td>
			</tr>
			<tr>
					<td style="text-align: center">-P</td>
					<td style="text-align: center">注意是大写的 P, port 是指定数据传输用到的端口号</td>
			</tr>
	</tbody>
</table>
<h2 id="使用实例">使用实例</h2>
<p>复制文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">scp local_file rmot_usr@rmot_ip:rmot_folder
</span></span><span class="line"><span class="cl">scp /opt/soft/ root@192.168.120.204:/opt/soft/nginx-0.5.38.tar.gz 
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-grep 文本搜索</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-grep%E6%96%87%E6%9C%AC%E6%90%9C%E7%B4%A2/</link>
      <pubDate>Thu, 05 Aug 2021 19:27:48 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-grep%E6%96%87%E6%9C%AC%E6%90%9C%E7%B4%A2/</guid>
      <description>&lt;p&gt;&lt;code&gt;grep&lt;/code&gt;全称&lt;code&gt;global search regular expression(RE) and print out the line&lt;/code&gt;，全面搜索正则表达式并把行打印出来。这名字就怪吓人，如果熟练掌握正则表达式，配上这命令 Linux 里可以横着走了。&lt;/p&gt;
&lt;p&gt;这个命令参数实在太多，加上正则表达式估计一张纸不够。那就直接上实例吧。&lt;/p&gt;
&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;p&gt;在当前目录中，查找后缀带有&lt;code&gt;cpp&lt;/code&gt;字样的文中包含&lt;code&gt;test&lt;/code&gt;字符串的文件，并打印所在行&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grep test *cpp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grep --colorauto test *cpp      # 用颜色标记
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过&amp;quot;-v&amp;quot;参数可以打印出不符合条件行的内容。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grep -v test *cpp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;系统报警显示了时间，但是日志文件太大无法直接 cat 查看。(查询含有特定文本的文件，并拿到这些文本所在的行)。&lt;code&gt;-n&lt;/code&gt; 或 &lt;code&gt;--line-number&lt;/code&gt; 可以显示符合样式的那一行之前，标示出该行的列数编号。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grep -n &amp;#39;2019-10-24 00:01:11&amp;#39; *.log
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;grep 静默输出，不会输出任何信息，如果命令运行成功返回 0，失败则返回非 0 值。一般用于条件测试。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grep -q &amp;#34;test&amp;#34; filename
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在多级目录中对文本进行递归搜索&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grep &amp;#34;text&amp;#34; . -r -n
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配合管道，查找指定的进程信息&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ps -ef | grep svn
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查找指定的进程个数，&lt;code&gt;-c&lt;/code&gt;计数&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ps -ef | grep svn -c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;常用正则表达式通配符&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;通配符&lt;/th&gt;
					&lt;th style=&#34;text-align: center&#34;&gt;功能&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;c*&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;将匹配 0 个（即空白）或多个字符 c（c 为任一字符）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;.&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;将匹配任何一个字符，且只能是一个字符&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;[xyz]&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;匹配方括号中的任意一个字符&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;[^xyz]&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;匹配除方括号中字符外的所有字符&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;^&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;锁定行的开头&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;$&lt;/td&gt;
					&lt;td style=&#34;text-align: center&#34;&gt;锁定行的结尾&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;在&lt;code&gt;id.txt&lt;/code&gt;中找到所有以 3207 开头的数据&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;grep ^3207 id.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p><code>grep</code>全称<code>global search regular expression(RE) and print out the line</code>，全面搜索正则表达式并把行打印出来。这名字就怪吓人，如果熟练掌握正则表达式，配上这命令 Linux 里可以横着走了。</p>
<p>这个命令参数实在太多，加上正则表达式估计一张纸不够。那就直接上实例吧。</p>
<h2 id="使用实例">使用实例</h2>
<p>在当前目录中，查找后缀带有<code>cpp</code>字样的文中包含<code>test</code>字符串的文件，并打印所在行</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">grep test *cpp
</span></span><span class="line"><span class="cl">grep --colorauto test *cpp      # 用颜色标记
</span></span></code></pre></div><p>通过&quot;-v&quot;参数可以打印出不符合条件行的内容。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">grep -v test *cpp
</span></span></code></pre></div><p>系统报警显示了时间，但是日志文件太大无法直接 cat 查看。(查询含有特定文本的文件，并拿到这些文本所在的行)。<code>-n</code> 或 <code>--line-number</code> 可以显示符合样式的那一行之前，标示出该行的列数编号。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">grep -n &#39;2019-10-24 00:01:11&#39; *.log
</span></span></code></pre></div><p>grep 静默输出，不会输出任何信息，如果命令运行成功返回 0，失败则返回非 0 值。一般用于条件测试。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">grep -q &#34;test&#34; filename
</span></span></code></pre></div><p>在多级目录中对文本进行递归搜索</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">grep &#34;text&#34; . -r -n
</span></span></code></pre></div><p>配合管道，查找指定的进程信息</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ps -ef | grep svn
</span></span></code></pre></div><p>查找指定的进程个数，<code>-c</code>计数</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ps -ef | grep svn -c
</span></span></code></pre></div><p>常用正则表达式通配符</p>
<table>
	<thead>
			<tr>
					<th style="text-align: center">通配符</th>
					<th style="text-align: center">功能</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: center">c*</td>
					<td style="text-align: center">将匹配 0 个（即空白）或多个字符 c（c 为任一字符）</td>
			</tr>
			<tr>
					<td style="text-align: center">.</td>
					<td style="text-align: center">将匹配任何一个字符，且只能是一个字符</td>
			</tr>
			<tr>
					<td style="text-align: center">[xyz]</td>
					<td style="text-align: center">匹配方括号中的任意一个字符</td>
			</tr>
			<tr>
					<td style="text-align: center">[^xyz]</td>
					<td style="text-align: center">匹配除方括号中字符外的所有字符</td>
			</tr>
			<tr>
					<td style="text-align: center">^</td>
					<td style="text-align: center">锁定行的开头</td>
			</tr>
			<tr>
					<td style="text-align: center">$</td>
					<td style="text-align: center">锁定行的结尾</td>
			</tr>
	</tbody>
</table>
<p>在<code>id.txt</code>中找到所有以 3207 开头的数据</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">grep ^3207 id.txt
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-cat 可以查看文件的小猫咪</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-cat%E5%8F%AF%E4%BB%A5%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6%E7%9A%84%E5%B0%8F%E7%8C%AB%E5%92%AA/</link>
      <pubDate>Wed, 04 Aug 2021 09:57:51 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-cat%E5%8F%AF%E4%BB%A5%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6%E7%9A%84%E5%B0%8F%E7%8C%AB%E5%92%AA/</guid>
      <description>&lt;p&gt;&lt;code&gt;cat&lt;/code&gt; 可以将文件的内容方便地输出到屏幕上。但是它的全称&lt;code&gt;concatenate&lt;/code&gt;意为“连接”，连接文件也是它的重要功能之一，很多人可能都不常用。只记得输出文件内容了。&lt;/p&gt;
&lt;h2 id=&#34;可选参数&#34;&gt;可选参数&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-n 或 --number              #由 1 开始对所有输出的行数编号。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-b 或 --number-nonblank     #和 -n 相似，只不过对于空白行不编号。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-s 或 --squeeze-blank       #当遇到有连续两行以上的空白行，就代换为一行的空白行。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-v 或 --show-nonprinting    #使用 ^ 和 M- 符号，除了 LFD 和 TAB 之外。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-E 或 --show-ends           # 在每行结束处显示 $。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-T 或 --show-tabs:          #将 TAB 字符显示为 ^I。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-A, --show-all              #等价于 -vET。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-e                          #等价于&amp;#34;-vE&amp;#34;选项；
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-t                          #等价于&amp;#34;-vT&amp;#34;选项；
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;p&gt;将文件内容输出到屏幕&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat test.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is firt line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is second line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is third line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is fourth line!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将&lt;code&gt;test.txt&lt;/code&gt;的内容输入到&lt;code&gt;test01.txt&lt;/code&gt;中&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat test.txt &amp;gt; test01.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat test01.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is firt line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is second line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is third line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is fourth line!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;带行号输出&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat -n test.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     1 This is firt line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     2 This is second line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     3 This is third line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     4 This is fourth line! 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将两个文件内容合并，再写入到第三个文件中&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat test.txt test01.txt &amp;gt;&amp;gt; test02.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat test02.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is firt line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is second line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is third line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is fourth line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is firt line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is second line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is third line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is fourth line!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;清空文件中的内容&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat /dev/null &amp;gt; test.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ cat test.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  ~ 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在类 Unix 系统中，/dev/null 称空设备，是一个特殊的设备文件，它丢弃一切写入其中的数据（但报告写入操作成功），读取它则会立即得到一个 EOF。&lt;/p&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://www.runoob.com/linux/linux-comm-cat.html&#34;&gt;https://www.runoob.com/linux/linux-comm-cat.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
      <content:encoded><![CDATA[<p><code>cat</code> 可以将文件的内容方便地输出到屏幕上。但是它的全称<code>concatenate</code>意为“连接”，连接文件也是它的重要功能之一，很多人可能都不常用。只记得输出文件内容了。</p>
<h2 id="可选参数">可选参数</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">-n 或 --number              #由 1 开始对所有输出的行数编号。
</span></span><span class="line"><span class="cl">-b 或 --number-nonblank     #和 -n 相似，只不过对于空白行不编号。
</span></span><span class="line"><span class="cl">-s 或 --squeeze-blank       #当遇到有连续两行以上的空白行，就代换为一行的空白行。
</span></span><span class="line"><span class="cl">-v 或 --show-nonprinting    #使用 ^ 和 M- 符号，除了 LFD 和 TAB 之外。
</span></span><span class="line"><span class="cl">-E 或 --show-ends           # 在每行结束处显示 $。
</span></span><span class="line"><span class="cl">-T 或 --show-tabs:          #将 TAB 字符显示为 ^I。
</span></span><span class="line"><span class="cl">-A, --show-all              #等价于 -vET。
</span></span><span class="line"><span class="cl">-e                          #等价于&#34;-vE&#34;选项；
</span></span><span class="line"><span class="cl">-t                          #等价于&#34;-vT&#34;选项；
</span></span></code></pre></div><h2 id="使用实例">使用实例</h2>
<p>将文件内容输出到屏幕</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ~ cat test.txt 
</span></span><span class="line"><span class="cl">This is firt line!
</span></span><span class="line"><span class="cl">This is second line!
</span></span><span class="line"><span class="cl">This is third line!
</span></span><span class="line"><span class="cl">This is fourth line!
</span></span></code></pre></div><p>将<code>test.txt</code>的内容输入到<code>test01.txt</code>中</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ~ cat test.txt &gt; test01.txt
</span></span><span class="line"><span class="cl">➜  ~ cat test01.txt 
</span></span><span class="line"><span class="cl">This is firt line!
</span></span><span class="line"><span class="cl">This is second line!
</span></span><span class="line"><span class="cl">This is third line!
</span></span><span class="line"><span class="cl">This is fourth line!
</span></span></code></pre></div><p>带行号输出</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ~ cat -n test.txt 
</span></span><span class="line"><span class="cl">     1 This is firt line!
</span></span><span class="line"><span class="cl">     2 This is second line!
</span></span><span class="line"><span class="cl">     3 This is third line!
</span></span><span class="line"><span class="cl">     4 This is fourth line! 
</span></span></code></pre></div><p>将两个文件内容合并，再写入到第三个文件中</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ~ cat test.txt test01.txt &gt;&gt; test02.txt
</span></span><span class="line"><span class="cl">➜  ~ cat test02.txt 
</span></span><span class="line"><span class="cl">This is firt line!
</span></span><span class="line"><span class="cl">This is second line!
</span></span><span class="line"><span class="cl">This is third line!
</span></span><span class="line"><span class="cl">This is fourth line!
</span></span><span class="line"><span class="cl">This is firt line!
</span></span><span class="line"><span class="cl">This is second line!
</span></span><span class="line"><span class="cl">This is third line!
</span></span><span class="line"><span class="cl">This is fourth line!
</span></span></code></pre></div><p>清空文件中的内容</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  ~ cat /dev/null &gt; test.txt 
</span></span><span class="line"><span class="cl">➜  ~ cat test.txt 
</span></span><span class="line"><span class="cl">➜  ~ 
</span></span></code></pre></div><p>在类 Unix 系统中，/dev/null 称空设备，是一个特殊的设备文件，它丢弃一切写入其中的数据（但报告写入操作成功），读取它则会立即得到一个 EOF。</p>
<h2 id="reference">Reference</h2>
<ol>
<li><a href="https://www.runoob.com/linux/linux-comm-cat.html">https://www.runoob.com/linux/linux-comm-cat.html</a></li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>解决/usr/bin/env:python:No such file or directory</title>
      <link>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3-usr-bin-env-python-no-such-file-or-directory/</link>
      <pubDate>Tue, 03 Aug 2021 15:58:44 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E8%A7%A3%E5%86%B3-usr-bin-env-python-no-such-file-or-directory/</guid>
      <description>&lt;p&gt;在执行的程序源码开头有这么一句&lt;code&gt;!#/usr/bin/env python&lt;/code&gt;，&lt;code&gt;!#&lt;/code&gt;这玩意叫&lt;code&gt;shebang&lt;/code&gt;也叫&lt;code&gt;hashbang&lt;/code&gt;。他用来指定脚本的解释器，也就是说这个程序指定&lt;code&gt;python&lt;/code&gt;解释器。&lt;/p&gt;
&lt;p&gt;再看这个错误提示，罪魁祸首就是这句命令，就是说在环境变量找不到&lt;code&gt;python&lt;/code&gt;，通俗点说，假如我要能直接用&lt;code&gt;python&lt;/code&gt;来跑这个程序，我在命令行直接输入&lt;code&gt;python&lt;/code&gt;应该是可以进入&lt;code&gt;python&lt;/code&gt;环境的，但是此时肯定不能。我们可以试试&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~$ python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Commond not found xxxxxxxxxxx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;解决方案一&#34;&gt;解决方案一&lt;/h2&gt;
&lt;p&gt;系统里没有&lt;code&gt;python&lt;/code&gt;还跑个锤子，先装上再说&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时候可能就解决问题了&lt;/p&gt;
&lt;h2 id=&#34;解决方案二&#34;&gt;解决方案二&lt;/h2&gt;
&lt;p&gt;有的人可能&lt;code&gt;python&lt;/code&gt;早就装了，但是仍然有这个问题，但是我们在命令输入&lt;code&gt;python&lt;/code&gt;仍然没法用，但是输入&lt;code&gt;python3&lt;/code&gt;就可以&lt;/p&gt;
&lt;p&gt;那&lt;code&gt;python3&lt;/code&gt;可以，我直接将&lt;code&gt;python&lt;/code&gt;改成&lt;code&gt;python3&lt;/code&gt;不就完了。没错！&lt;/p&gt;
&lt;p&gt;打开文件将&lt;code&gt;!#/usr/bin/env python&lt;/code&gt;改成&lt;code&gt;!#/usr/bin/env python3&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;解决方案三&#34;&gt;解决方案三&lt;/h2&gt;
&lt;p&gt;如果了解软链接，那我们就可以不用去改源码了，源码最好还是保持原样。&lt;/p&gt;
&lt;p&gt;既然找不到&lt;code&gt;python&lt;/code&gt;这玩意，那我们给他建一个不就完了。&lt;/p&gt;
&lt;p&gt;他要&lt;code&gt;python&lt;/code&gt;就是用来解释程序的，我们本地装的&lt;code&gt;python3&lt;/code&gt;就是他需要的东西&lt;/p&gt;
&lt;p&gt;先找找我们的&lt;code&gt;python3&lt;/code&gt;在哪&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~$ whereis python3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3: /usr/bin/python3.8 /usr/bin/python3.8-config /usr/bin/python3 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一般在&lt;code&gt;/usr/bin&lt;/code&gt;目录下，然后我们在这个目录下给他创建一个软链接“快捷方式”，具体咋用的啥意思，可以&lt;a href=&#34;https://dunky-z.github.io/2021/08/03/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ln%E8%BD%AF%E7%A1%AC%E9%93%BE%E6%8E%A5/&#34;&gt;参考这篇文章&lt;/a&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo ln -s /usr/bin/python3 /usr/bin/python
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样程序再找&lt;code&gt;python&lt;/code&gt;时就会链接到&lt;code&gt;python3&lt;/code&gt;，然后用&lt;code&gt;python3&lt;/code&gt;去当解释器。&lt;/p&gt;
&lt;h2 id=&#34;解决方案四&#34;&gt;解决方案四&lt;/h2&gt;
&lt;p&gt;可能在&lt;code&gt;root&lt;/code&gt;目录下使用过&lt;code&gt;repo&lt;/code&gt;，将其删除&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>在执行的程序源码开头有这么一句<code>!#/usr/bin/env python</code>，<code>!#</code>这玩意叫<code>shebang</code>也叫<code>hashbang</code>。他用来指定脚本的解释器，也就是说这个程序指定<code>python</code>解释器。</p>
<p>再看这个错误提示，罪魁祸首就是这句命令，就是说在环境变量找不到<code>python</code>，通俗点说，假如我要能直接用<code>python</code>来跑这个程序，我在命令行直接输入<code>python</code>应该是可以进入<code>python</code>环境的，但是此时肯定不能。我们可以试试</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:~$ python
</span></span><span class="line"><span class="cl">Commond not found xxxxxxxxxxx
</span></span></code></pre></div><h2 id="解决方案一">解决方案一</h2>
<p>系统里没有<code>python</code>还跑个锤子，先装上再说</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt-get install python3
</span></span></code></pre></div><p>这时候可能就解决问题了</p>
<h2 id="解决方案二">解决方案二</h2>
<p>有的人可能<code>python</code>早就装了，但是仍然有这个问题，但是我们在命令输入<code>python</code>仍然没法用，但是输入<code>python3</code>就可以</p>
<p>那<code>python3</code>可以，我直接将<code>python</code>改成<code>python3</code>不就完了。没错！</p>
<p>打开文件将<code>!#/usr/bin/env python</code>改成<code>!#/usr/bin/env python3</code></p>
<h2 id="解决方案三">解决方案三</h2>
<p>如果了解软链接，那我们就可以不用去改源码了，源码最好还是保持原样。</p>
<p>既然找不到<code>python</code>这玩意，那我们给他建一个不就完了。</p>
<p>他要<code>python</code>就是用来解释程序的，我们本地装的<code>python3</code>就是他需要的东西</p>
<p>先找找我们的<code>python3</code>在哪</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:~$ whereis python3
</span></span><span class="line"><span class="cl">python3: /usr/bin/python3.8 /usr/bin/python3.8-config /usr/bin/python3 
</span></span></code></pre></div><p>一般在<code>/usr/bin</code>目录下，然后我们在这个目录下给他创建一个软链接“快捷方式”，具体咋用的啥意思，可以<a href="https://dunky-z.github.io/2021/08/03/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ln%E8%BD%AF%E7%A1%AC%E9%93%BE%E6%8E%A5/">参考这篇文章</a>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo ln -s /usr/bin/python3 /usr/bin/python
</span></span></code></pre></div><p>这样程序再找<code>python</code>时就会链接到<code>python3</code>，然后用<code>python3</code>去当解释器。</p>
<h2 id="解决方案四">解决方案四</h2>
<p>可能在<code>root</code>目录下使用过<code>repo</code>，将其删除</p>
]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-ln 软硬链接</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ln%E8%BD%AF%E7%A1%AC%E9%93%BE%E6%8E%A5/</link>
      <pubDate>Tue, 03 Aug 2021 11:57:02 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ln%E8%BD%AF%E7%A1%AC%E9%93%BE%E6%8E%A5/</guid>
      <description>&lt;p&gt;Linux ln（英文全拼：link files）命令是一个非常重要命令，它的功能是为某一个文件在另外一个位置建立一个同步的链接。这有点像 Windows 环境下的快捷方式。介绍命令前了解一下软链接，硬链接具体是什么。&lt;/p&gt;
&lt;h2 id=&#34;硬链接-hard-link&#34;&gt;硬链接 Hard Link&lt;/h2&gt;
&lt;p&gt;在 Linux 系统中，每个文件对应一个 &lt;code&gt;inode&lt;/code&gt;，文件的内容在存储在 &lt;code&gt;inode&lt;/code&gt; 指向的 &lt;code&gt;data block&lt;/code&gt; 中。要读取该文件的内容，需要通过文件所在的目录中记录的&lt;strong&gt;文件名&lt;/strong&gt;找到文件的 &lt;code&gt;inode&lt;/code&gt; 号，然后通过 &lt;code&gt;inode&lt;/code&gt; 找到存储文件内容的 &lt;code&gt;data block&lt;/code&gt;。当然多个&lt;strong&gt;文件名&lt;/strong&gt;可以指向同一个&lt;code&gt;inode&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;ll&lt;/code&gt;命令显示文件的详细信息，&lt;code&gt;-i&lt;/code&gt;参数显示其结点信息，其中最前面的一串数字就是&lt;code&gt;inode&lt;/code&gt;信息。我们以&lt;code&gt;/opt/test.txt&lt;/code&gt;文件为例，查看其结点信息。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:/opt$ ll -i test.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2498138 -rw-r--r-- 1 root root 4 8月   3 12:16 test.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;ln&lt;/code&gt; 命令在&lt;code&gt;/opt/temp&lt;/code&gt;目录下创建一个 &lt;code&gt;test.txt&lt;/code&gt; 文件的硬链接，然后观察其文件属性：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:/opt/temp$ sudo ln ../test.txt .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:/opt/temp$ ll -i ../test.txt test.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2498138 -rw-r--r-- 2 root root 4 8月   3 12:16 ../test.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2498138 -rw-r--r-- 2 root root 4 8月   3 12:16 test.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们再用&lt;code&gt;ll -i&lt;/code&gt;命令查看结点信息，发现这两个文件名的结点信息是一样的。说明这两个文件名指向的是同一个文件。其中第三个字段是&lt;strong&gt;链接数&lt;/strong&gt;，数字&lt;code&gt;2&lt;/code&gt;，表示有两个文件名链接到同一个&lt;code&gt;inode&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id=&#34;硬链接的特点&#34;&gt;硬链接的特点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;硬链接，以文件副本的形式存在。但不占用实际空间。
由于硬链接只是在目录中添加了一条包含文件名和 对应 inode 的记录，所以它几乎不会消耗额外的磁盘容量。&lt;/li&gt;
&lt;li&gt;不允许给目录创建硬链接&lt;/li&gt;
&lt;li&gt;硬链接只有在同一个文件系统中才能创建&lt;/li&gt;
&lt;li&gt;只要还有一个文件名引用着文件，文件就不会被真正删除
删除硬链接所关联的文件时，其实只是删除了一条目录中的记录，真正的文件并不受影响。只有在删除最后一个硬链接时才会真正删除文件的内容数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;软链接-symbolic-link&#34;&gt;软链接 Symbolic Link&lt;/h2&gt;
&lt;p&gt;软链接的实现方式与硬链接有本质上的不同。创建软链接时会创建一个新的文件 (分配一个&lt;code&gt;inode&lt;/code&gt; 和对应的 &lt;code&gt;data block&lt;/code&gt;)，新文件的 &lt;code&gt;data block&lt;/code&gt; 中存储了目标文件的路径。&lt;/p&gt;
&lt;p&gt;我们以&lt;code&gt;/opt/test.txt&lt;/code&gt;为例，在&lt;code&gt;/opt/temp&lt;/code&gt;目录中，为其创建一个软链接，然后查看其&lt;code&gt;inode&lt;/code&gt;结点信息。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:/opt/temp$ sudo ln -s ../test.txt test2.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:/opt/temp$ ll -i ../test.txt test2.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2498139 lrwxrwxrwx 1 root root 11 8月   3 14:01 test2.txt -&amp;gt; ../test.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2498138 -rw-r--r-- 2 root root  4 8月   3 12:16 ../test.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;第一个字段不同，说明是两个文件了&lt;/li&gt;
&lt;li&gt;第二个字段表示权限，第一个字母表示文件类型，&lt;code&gt;l&lt;/code&gt;说明书软链接文件&lt;/li&gt;
&lt;li&gt;第三个字段表示链接数，仍然是&lt;code&gt;2&lt;/code&gt;，说明软链接不增加源文件链接数&lt;/li&gt;
&lt;li&gt;第六个字段是文件大小，新建的软链接文件时 11 字节，这就是&lt;code&gt;/opt/test.txt&lt;/code&gt;的长度。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;软链接特点&#34;&gt;软链接特点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;软链接，以路径的形式存在。类似于 Windows 操作系统中的快捷方式&lt;/li&gt;
&lt;li&gt;软链接可以 跨文件系统，硬链接不可以&lt;/li&gt;
&lt;li&gt;软链接可以对一个不存在的文件名进行链接&lt;/li&gt;
&lt;li&gt;软链接可以对目录进行链接&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;p&gt;ln [参数][源文件或目录][目标文件或目录]
为文件&lt;code&gt;test.txt&lt;/code&gt;创建一个硬链接&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo ln test.txt /etc/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;删除&lt;code&gt;test.txt&lt;/code&gt;的硬链接，因为是以副本形式存在的，所以直接用&lt;code&gt;rm&lt;/code&gt;命令将其删除即可。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo rm /etc/test.txt 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为文件&lt;code&gt;test.txt&lt;/code&gt;创建一个软链接&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo ln -s test.txt /etc/test2.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;删除软链接也一样，直接用&lt;code&gt;rm&lt;/code&gt;命令删除软链接的名称即可。&lt;/p&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.runoob.com/linux/linux-comm-ln.html&#34;&gt;https://www.runoob.com/linux/linux-comm-ln.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/lixuze/p/14248559.html&#34;&gt;https://www.cnblogs.com/lixuze/p/14248559.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<p>Linux ln（英文全拼：link files）命令是一个非常重要命令，它的功能是为某一个文件在另外一个位置建立一个同步的链接。这有点像 Windows 环境下的快捷方式。介绍命令前了解一下软链接，硬链接具体是什么。</p>
<h2 id="硬链接-hard-link">硬链接 Hard Link</h2>
<p>在 Linux 系统中，每个文件对应一个 <code>inode</code>，文件的内容在存储在 <code>inode</code> 指向的 <code>data block</code> 中。要读取该文件的内容，需要通过文件所在的目录中记录的<strong>文件名</strong>找到文件的 <code>inode</code> 号，然后通过 <code>inode</code> 找到存储文件内容的 <code>data block</code>。当然多个<strong>文件名</strong>可以指向同一个<code>inode</code>。</p>
<p>使用<code>ll</code>命令显示文件的详细信息，<code>-i</code>参数显示其结点信息，其中最前面的一串数字就是<code>inode</code>信息。我们以<code>/opt/test.txt</code>文件为例，查看其结点信息。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:/opt$ ll -i test.txt 
</span></span><span class="line"><span class="cl">2498138 -rw-r--r-- 1 root root 4 8月   3 12:16 test.txt
</span></span></code></pre></div><p>使用 <code>ln</code> 命令在<code>/opt/temp</code>目录下创建一个 <code>test.txt</code> 文件的硬链接，然后观察其文件属性：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:/opt/temp$ sudo ln ../test.txt .
</span></span><span class="line"><span class="cl">dominic@hanhan:/opt/temp$ ll -i ../test.txt test.txt 
</span></span><span class="line"><span class="cl">2498138 -rw-r--r-- 2 root root 4 8月   3 12:16 ../test.txt
</span></span><span class="line"><span class="cl">2498138 -rw-r--r-- 2 root root 4 8月   3 12:16 test.txt
</span></span></code></pre></div><p>我们再用<code>ll -i</code>命令查看结点信息，发现这两个文件名的结点信息是一样的。说明这两个文件名指向的是同一个文件。其中第三个字段是<strong>链接数</strong>，数字<code>2</code>，表示有两个文件名链接到同一个<code>inode</code>。</p>
<h4 id="硬链接的特点">硬链接的特点</h4>
<ul>
<li>硬链接，以文件副本的形式存在。但不占用实际空间。
由于硬链接只是在目录中添加了一条包含文件名和 对应 inode 的记录，所以它几乎不会消耗额外的磁盘容量。</li>
<li>不允许给目录创建硬链接</li>
<li>硬链接只有在同一个文件系统中才能创建</li>
<li>只要还有一个文件名引用着文件，文件就不会被真正删除
删除硬链接所关联的文件时，其实只是删除了一条目录中的记录，真正的文件并不受影响。只有在删除最后一个硬链接时才会真正删除文件的内容数据。</li>
</ul>
<h2 id="软链接-symbolic-link">软链接 Symbolic Link</h2>
<p>软链接的实现方式与硬链接有本质上的不同。创建软链接时会创建一个新的文件 (分配一个<code>inode</code> 和对应的 <code>data block</code>)，新文件的 <code>data block</code> 中存储了目标文件的路径。</p>
<p>我们以<code>/opt/test.txt</code>为例，在<code>/opt/temp</code>目录中，为其创建一个软链接，然后查看其<code>inode</code>结点信息。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:/opt/temp$ sudo ln -s ../test.txt test2.txt
</span></span><span class="line"><span class="cl">dominic@hanhan:/opt/temp$ ll -i ../test.txt test2.txt 
</span></span><span class="line"><span class="cl">2498139 lrwxrwxrwx 1 root root 11 8月   3 14:01 test2.txt -&gt; ../test.txt
</span></span><span class="line"><span class="cl">2498138 -rw-r--r-- 2 root root  4 8月   3 12:16 ../test.txt
</span></span></code></pre></div><ul>
<li>第一个字段不同，说明是两个文件了</li>
<li>第二个字段表示权限，第一个字母表示文件类型，<code>l</code>说明书软链接文件</li>
<li>第三个字段表示链接数，仍然是<code>2</code>，说明软链接不增加源文件链接数</li>
<li>第六个字段是文件大小，新建的软链接文件时 11 字节，这就是<code>/opt/test.txt</code>的长度。</li>
</ul>
<h4 id="软链接特点">软链接特点</h4>
<ul>
<li>软链接，以路径的形式存在。类似于 Windows 操作系统中的快捷方式</li>
<li>软链接可以 跨文件系统，硬链接不可以</li>
<li>软链接可以对一个不存在的文件名进行链接</li>
<li>软链接可以对目录进行链接</li>
</ul>
<h2 id="使用实例">使用实例</h2>
<p>ln [参数][源文件或目录][目标文件或目录]
为文件<code>test.txt</code>创建一个硬链接</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo ln test.txt /etc/
</span></span></code></pre></div><p>删除<code>test.txt</code>的硬链接，因为是以副本形式存在的，所以直接用<code>rm</code>命令将其删除即可。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo rm /etc/test.txt 
</span></span></code></pre></div><p>为文件<code>test.txt</code>创建一个软链接</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo ln -s test.txt /etc/test2.txt
</span></span></code></pre></div><p>删除软链接也一样，直接用<code>rm</code>命令删除软链接的名称即可。</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://www.runoob.com/linux/linux-comm-ln.html">https://www.runoob.com/linux/linux-comm-ln.html</a></li>
<li><a href="https://www.cnblogs.com/lixuze/p/14248559.html">https://www.cnblogs.com/lixuze/p/14248559.html</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-ed 行编辑器</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ed%E8%A1%8C%E7%BC%96%E8%BE%91%E5%99%A8/</link>
      <pubDate>Mon, 02 Aug 2021 09:57:10 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-ed%E8%A1%8C%E7%BC%96%E8%BE%91%E5%99%A8/</guid>
      <description>&lt;p&gt;&lt;code&gt;ed&lt;/code&gt;命令是文本编辑器，用于文本编辑。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ed&lt;/code&gt;是 Linux 中功能最简单的文本编辑程序，一次仅能编辑一行而非全屏幕方式的操作。很多命令和&lt;code&gt;vim&lt;/code&gt;相似，平时开发中并不常用，但是在编辑大文本时还是会用到。&lt;/p&gt;
&lt;p&gt;学学无妨毕竟这是 Unix 系统三大要件（编辑器，汇编器和 shell）之一。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ed&lt;/code&gt;编辑器有两种模式：命令模式和输入模式。命令模式下输入&lt;code&gt;a&lt;/code&gt;,&lt;code&gt;i&lt;/code&gt;,&lt;code&gt;c&lt;/code&gt;,&lt;code&gt;d&lt;/code&gt;可以进入对应的编辑模式，接下来可以输入任何想要输入的内容，输入完毕或者要切换命令时，可以输入&lt;code&gt;.&lt;/code&gt;退出输入模式。&lt;/p&gt;
&lt;h2 id=&#34;commands&#34;&gt;Commands&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a           #添加到行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;i           #添加到行首
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;c           #改变行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;d           #删除行
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;line-address&#34;&gt;Line Address&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;. #buffer 中 当前行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ #最后一行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;n #第 n 行，行的范围是 [0,$]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- or ^ #前一行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-n or ^n #前 n 行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+ or +n #后一行及后n行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;, or % #全部行，等同于 1,$
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;; #当前行到最后一行 .,$
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/re/ #下一个包含正则 re 的行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;?re? #上一个包含正则 re 的行
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~$ ed                # 进入编辑模式
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is a test text!                # 输入文本
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.               # 结束输入命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is a test text!                # 回显当前行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;n               # 显示行号命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1 This is a test text!        # 回显当前行并显示行号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;c               # 改变行命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is changed text!               # 输入更改后的内容
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.               # 结束输入命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;n               # 显示行号命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1 This is changed text!       # 回显当前行并显示行号
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;i               # 在首行插入命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is first line!                 # 输入插入内容
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.               # 结束输入命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;+               # 后一行命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is changed text!               # 回显后一行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;d               # 删除当前行 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.               # 回显当前行命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is firt line!                  # 回显当前行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is second line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is third line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is fourth line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;w test.txt      # 写入并保存文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;q               # 退出编辑器
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~$ cat test.txt      # 查看内容
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is first line!s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is second line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is third line!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is fourth line!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p><code>ed</code>命令是文本编辑器，用于文本编辑。</p>
<p><code>ed</code>是 Linux 中功能最简单的文本编辑程序，一次仅能编辑一行而非全屏幕方式的操作。很多命令和<code>vim</code>相似，平时开发中并不常用，但是在编辑大文本时还是会用到。</p>
<p>学学无妨毕竟这是 Unix 系统三大要件（编辑器，汇编器和 shell）之一。</p>
<p><code>ed</code>编辑器有两种模式：命令模式和输入模式。命令模式下输入<code>a</code>,<code>i</code>,<code>c</code>,<code>d</code>可以进入对应的编辑模式，接下来可以输入任何想要输入的内容，输入完毕或者要切换命令时，可以输入<code>.</code>退出输入模式。</p>
<h2 id="commands">Commands</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">a           #添加到行
</span></span><span class="line"><span class="cl">i           #添加到行首
</span></span><span class="line"><span class="cl">c           #改变行
</span></span><span class="line"><span class="cl">d           #删除行
</span></span></code></pre></div><h2 id="line-address">Line Address</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">. #buffer 中 当前行
</span></span><span class="line"><span class="cl">$ #最后一行
</span></span><span class="line"><span class="cl">n #第 n 行，行的范围是 [0,$]
</span></span><span class="line"><span class="cl">- or ^ #前一行
</span></span><span class="line"><span class="cl">-n or ^n #前 n 行
</span></span><span class="line"><span class="cl">+ or +n #后一行及后n行
</span></span><span class="line"><span class="cl">, or % #全部行，等同于 1,$
</span></span><span class="line"><span class="cl">; #当前行到最后一行 .,$
</span></span><span class="line"><span class="cl">/re/ #下一个包含正则 re 的行
</span></span><span class="line"><span class="cl">?re? #上一个包含正则 re 的行
</span></span></code></pre></div><h2 id="使用实例">使用实例</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:~$ ed                # 进入编辑模式
</span></span><span class="line"><span class="cl">This is a test text!                # 输入文本
</span></span><span class="line"><span class="cl">.               # 结束输入命令
</span></span><span class="line"><span class="cl">This is a test text!                # 回显当前行
</span></span><span class="line"><span class="cl">n               # 显示行号命令
</span></span><span class="line"><span class="cl">1 This is a test text!        # 回显当前行并显示行号
</span></span><span class="line"><span class="cl">c               # 改变行命令
</span></span><span class="line"><span class="cl">This is changed text!               # 输入更改后的内容
</span></span><span class="line"><span class="cl">.               # 结束输入命令
</span></span><span class="line"><span class="cl">n               # 显示行号命令
</span></span><span class="line"><span class="cl">1 This is changed text!       # 回显当前行并显示行号
</span></span><span class="line"><span class="cl">i               # 在首行插入命令
</span></span><span class="line"><span class="cl">This is first line!                 # 输入插入内容
</span></span><span class="line"><span class="cl">.               # 结束输入命令
</span></span><span class="line"><span class="cl">+               # 后一行命令
</span></span><span class="line"><span class="cl">This is changed text!               # 回显后一行
</span></span><span class="line"><span class="cl">d               # 删除当前行 
</span></span><span class="line"><span class="cl">.               # 回显当前行命令
</span></span><span class="line"><span class="cl">This is firt line!                  # 回显当前行
</span></span><span class="line"><span class="cl">a
</span></span><span class="line"><span class="cl">This is second line!
</span></span><span class="line"><span class="cl">This is third line!
</span></span><span class="line"><span class="cl">This is fourth line!
</span></span><span class="line"><span class="cl">w test.txt      # 写入并保存文件
</span></span><span class="line"><span class="cl">q               # 退出编辑器
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">dominic@hanhan:~$ cat test.txt      # 查看内容
</span></span><span class="line"><span class="cl">This is first line!s
</span></span><span class="line"><span class="cl">This is second line!
</span></span><span class="line"><span class="cl">This is third line!
</span></span><span class="line"><span class="cl">This is fourth line!
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-wc 统计文件有多少字多少行</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-wc%E7%BB%9F%E8%AE%A1%E6%96%87%E4%BB%B6%E6%9C%89%E5%A4%9A%E5%B0%91%E5%AD%97%E5%A4%9A%E5%B0%91%E8%A1%8C/</link>
      <pubDate>Fri, 30 Jul 2021 17:26:39 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-wc%E7%BB%9F%E8%AE%A1%E6%96%87%E4%BB%B6%E6%9C%89%E5%A4%9A%E5%B0%91%E5%AD%97%E5%A4%9A%E5%B0%91%E8%A1%8C/</guid>
      <description>&lt;p&gt;想知道自己代码写了多少行，可以一个&lt;code&gt;wc&lt;/code&gt;命令搞定。&lt;/p&gt;
&lt;h2 id=&#34;可选参数&#34;&gt;可选参数&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-l：仅列出行；
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-w：仅列出多少字 (英文单字)；
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-m：多少字符
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;p&gt;统计&lt;code&gt;hello.c&lt;/code&gt;文件夹下文件总共多少行&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ wc -l  hello.c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;14&lt;/span&gt; hello.c
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;统计文件夹下文件的个数&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls -l &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;^-&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; wc -l
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;统计当前目录下文件的个数（包括子目录）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls -lR&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;^-&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; wc -l
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看目录下文件夹 (目录) 的个数（包括子目录）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls -lR &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;^d&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; wc -l
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;过滤&lt;code&gt;ls&lt;/code&gt;的输出信息，只保留一般文件，只保留目录是&lt;code&gt;grep &amp;quot;^d&amp;quot;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<p>想知道自己代码写了多少行，可以一个<code>wc</code>命令搞定。</p>
<h2 id="可选参数">可选参数</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">-l：仅列出行；
</span></span><span class="line"><span class="cl">-w：仅列出多少字 (英文单字)；
</span></span><span class="line"><span class="cl">-m：多少字符
</span></span></code></pre></div><h2 id="使用实例">使用实例</h2>
<p>统计<code>hello.c</code>文件夹下文件总共多少行</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">$ wc -l  hello.c
</span></span><span class="line"><span class="cl"><span class="m">14</span> hello.c
</span></span></code></pre></div><p>统计文件夹下文件的个数</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">ls -l <span class="p">|</span> grep <span class="s2">&#34;^-&#34;</span> <span class="p">|</span> wc -l
</span></span></code></pre></div><p>统计当前目录下文件的个数（包括子目录）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">ls -lR<span class="p">|</span> grep <span class="s2">&#34;^-&#34;</span> <span class="p">|</span> wc -l
</span></span></code></pre></div><p>查看目录下文件夹 (目录) 的个数（包括子目录）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">ls -lR <span class="p">|</span> grep <span class="s2">&#34;^d&#34;</span> <span class="p">|</span> wc -l
</span></span></code></pre></div><ul>
<li>过滤<code>ls</code>的输出信息，只保留一般文件，只保留目录是<code>grep &quot;^d&quot;</code>。</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>更换 Ubuntu 软件更新源</title>
      <link>https://lifeislife.cn/posts/linux%E6%9B%B4%E6%8D%A2ubuntu%E8%BD%AF%E4%BB%B6%E6%9B%B4%E6%96%B0%E6%BA%90/</link>
      <pubDate>Fri, 30 Jul 2021 11:14:41 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E6%9B%B4%E6%8D%A2ubuntu%E8%BD%AF%E4%BB%B6%E6%9B%B4%E6%96%B0%E6%BA%90/</guid>
      <description>&lt;p&gt;Ubuntu 默认是国外的源，软件下载和更新都比较慢。两种方法将下载源换成国内的源。&lt;/p&gt;
&lt;h2 id=&#34;用软件和更新工具&#34;&gt;用&amp;quot;软件和更新&amp;quot;工具&lt;/h2&gt;
&lt;p&gt;从 Ubuntu 菜单中找到&lt;strong&gt;软件和更新&lt;/strong&gt;这个应用并打开。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730112638.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730112638.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;找到&lt;strong&gt;下载自&lt;/strong&gt;，选择&lt;strong&gt;其他 - 国内-aliyun&lt;/strong&gt;，然后勾选前四个选项。关闭时会弹出对话框，点击&lt;strong&gt;更新&lt;/strong&gt;。然后就能愉&lt;strong&gt;快&lt;/strong&gt;的下载软件了。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730113029.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730113029.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;修改sourcelist&#34;&gt;修改&lt;code&gt;sourcelist&lt;/code&gt;&lt;/h2&gt;
&lt;h3 id=&#34;备份原文件&#34;&gt;备份原文件&lt;/h3&gt;
&lt;p&gt;这也算是系统文件的一部分，还是保险一点，出错了再改回来。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;打开并修改&#34;&gt;打开并修改&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo vi /etc/apt/sources.list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;vim&lt;/code&gt;用的不习惯的估计会和我一样找全选内容怎么操作。教给你了
在命令模式下，就是按一下&lt;code&gt;esc&lt;/code&gt;键，然后输入&lt;code&gt;ggvG&lt;/code&gt;。具体什么含义看&lt;code&gt;VIM 笔记&lt;/code&gt;吧，选择后直接&lt;code&gt;delete&lt;/code&gt;删除，再把阿里云源粘贴进去。保存退出。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#阿里云&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;更新&#34;&gt;更新&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get dist-upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>Ubuntu 默认是国外的源，软件下载和更新都比较慢。两种方法将下载源换成国内的源。</p>
<h2 id="用软件和更新工具">用&quot;软件和更新&quot;工具</h2>
<p>从 Ubuntu 菜单中找到<strong>软件和更新</strong>这个应用并打开。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730112638.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730112638.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>找到<strong>下载自</strong>，选择<strong>其他 - 国内-aliyun</strong>，然后勾选前四个选项。关闭时会弹出对话框，点击<strong>更新</strong>。然后就能愉<strong>快</strong>的下载软件了。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730113029.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730113029.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="修改sourcelist">修改<code>sourcelist</code></h2>
<h3 id="备份原文件">备份原文件</h3>
<p>这也算是系统文件的一部分，还是保险一点，出错了再改回来。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
</span></span></code></pre></div><h3 id="打开并修改">打开并修改</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo vi /etc/apt/sources.list
</span></span></code></pre></div><p><code>vim</code>用的不习惯的估计会和我一样找全选内容怎么操作。教给你了
在命令模式下，就是按一下<code>esc</code>键，然后输入<code>ggvG</code>。具体什么含义看<code>VIM 笔记</code>吧，选择后直接<code>delete</code>删除，再把阿里云源粘贴进去。保存退出。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#阿里云</span>
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
</span></span><span class="line"><span class="cl">deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
</span></span></code></pre></div><h2 id="更新">更新</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt-get update
</span></span><span class="line"><span class="cl">sudo apt-get dist-upgrade
</span></span><span class="line"><span class="cl">sudo apt-get upgrade
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-find 查找文件</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-find%E6%9F%A5%E6%89%BE%E6%96%87%E4%BB%B6/</link>
      <pubDate>Thu, 29 Jul 2021 11:05:43 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-find%E6%9F%A5%E6%89%BE%E6%96%87%E4%BB%B6/</guid>
      <description>&lt;h2 id=&#34;命令格式&#34;&gt;命令格式&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find [path] [expression]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;path&lt;/code&gt;下查找&lt;code&gt;expression&lt;/code&gt;表示的文件&lt;/p&gt;
&lt;h2 id=&#34;常用命令&#34;&gt;常用命令&lt;/h2&gt;
&lt;p&gt;一般常见就是自己不知道写的某个文件或者文件夹放哪里了，又或者只记住部分文件名。以下几个命令就能帮到你。&lt;/p&gt;
&lt;h3 id=&#34;按文件名查找&#34;&gt;按文件名查找&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find  -name filename(查找结果显示路径)或者 find filename(查找结果不显示路径)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find hello.cpp          #当前目录下精确查找hello.cpp文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find hello              #当前目录下精确查找hello文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find hello*             #当前目录下模糊查找以hello为前缀的文件
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;按类型查找&#34;&gt;按类型查找&lt;/h3&gt;
&lt;p&gt;这就是为查找文件夹用的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find -type [fdlcb] name
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;[fdlcb]&lt;/code&gt;都是类型，&lt;code&gt;d&lt;/code&gt;就是目录，文件夹类型。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find / -type d -name &amp;#34;helloworld&amp;#34;   #查找名为helloworld的文件夹
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;按文件名查找-1&#34;&gt;按文件名查找&lt;/h2&gt;
&lt;p&gt;以下就详细介绍一些参数&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find -name &amp;#34;hello.cpp&amp;#34;              # 搜索文件名，大小写敏感
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find -iname &amp;#34;hello.cpp&amp;#34;             #大小写不敏感
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;按文件大小查找&#34;&gt;按文件大小查找&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find [path] -size 50M
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find / -size 10M                # 查找系统中大小等于10M的文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find / -size +50M               # 查找系统中大小大于50M的文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find  / -size -30M              # 查找系统中大小小于30M的文件
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;按时间来查找文件&#34;&gt;按时间来查找文件&lt;/h2&gt;
&lt;p&gt;Linux 会存储下面的时间：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access time 上一次文件读或者写的时间&lt;/li&gt;
&lt;li&gt;Modifica time 上一次文件被修改的时间&lt;/li&gt;
&lt;li&gt;Change time 上一次文件 &lt;code&gt;inode meta&lt;/code&gt; 信息被修改的时间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在按照时间查找时，可以使用 &lt;code&gt;-atime&lt;/code&gt;， &lt;code&gt;-mtime&lt;/code&gt; 或者 &lt;code&gt;-ctime&lt;/code&gt;，和之前 &lt;code&gt;size&lt;/code&gt;参数一样可以使用 &lt;code&gt;+&lt;/code&gt; 或者 &lt;code&gt;-&lt;/code&gt;时间范围，下图表示&lt;code&gt;find&lt;/code&gt;的时间轴。&lt;code&gt;+&lt;/code&gt;表示超过多少天，&lt;code&gt;-&lt;/code&gt;表示多少天以内。&lt;/p&gt;
&lt;p&gt;此外，也可以换成&lt;code&gt;-amin&lt;/code&gt;， &lt;code&gt;-mmin&lt;/code&gt; 或者 &lt;code&gt;-cmin&lt;/code&gt;参数，单位是分钟。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210729151915.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210729151915.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find / -mtime 1          # 寻找修改时间超过一天的文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find / -atime -1         # 寻找在一天时间内被访问的文件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find / -ctime +3         # 寻找 meta 信息被修改的时间超过 3 天的文件
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;http://c.biancheng.net/view/779.html&#34;&gt;http://c.biancheng.net/view/779.html&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://einverne.github.io/post/2018/02/find-command.html#%E6%89%B9%E9%87%8F%E5%88%A0%E9%99%A4%E6%97%B6%E9%97%B4%E8%B6%85%E8%BF%87-1-%E5%A4%A9%E7%9A%84%E6%96%87%E4%BB%B6&#34;&gt;https://einverne.github.io/post/2018/02/find-command.html#%E6%89%B9%E9%87%8F%E5%88%A0%E9%99%A4%E6%97%B6%E9%97%B4%E8%B6%85%E8%BF%87-1-%E5%A4%A9%E7%9A%84%E6%96%87%E4%BB%B6&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</description>
      <content:encoded><![CDATA[<h2 id="命令格式">命令格式</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">find [path] [expression]
</span></span></code></pre></div><p>在<code>path</code>下查找<code>expression</code>表示的文件</p>
<h2 id="常用命令">常用命令</h2>
<p>一般常见就是自己不知道写的某个文件或者文件夹放哪里了，又或者只记住部分文件名。以下几个命令就能帮到你。</p>
<h3 id="按文件名查找">按文件名查找</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">find  -name filename(查找结果显示路径)或者 find filename(查找结果不显示路径)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">find hello.cpp          #当前目录下精确查找hello.cpp文件
</span></span><span class="line"><span class="cl">find hello              #当前目录下精确查找hello文件
</span></span><span class="line"><span class="cl">find hello*             #当前目录下模糊查找以hello为前缀的文件
</span></span></code></pre></div><h3 id="按类型查找">按类型查找</h3>
<p>这就是为查找文件夹用的。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">find -type [fdlcb] name
</span></span></code></pre></div><p><code>[fdlcb]</code>都是类型，<code>d</code>就是目录，文件夹类型。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">find / -type d -name &#34;helloworld&#34;   #查找名为helloworld的文件夹
</span></span></code></pre></div><h2 id="按文件名查找-1">按文件名查找</h2>
<p>以下就详细介绍一些参数</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">find -name &#34;hello.cpp&#34;              # 搜索文件名，大小写敏感
</span></span><span class="line"><span class="cl">find -iname &#34;hello.cpp&#34;             #大小写不敏感
</span></span></code></pre></div><h2 id="按文件大小查找">按文件大小查找</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">find [path] -size 50M
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">find / -size 10M                # 查找系统中大小等于10M的文件
</span></span><span class="line"><span class="cl">find / -size +50M               # 查找系统中大小大于50M的文件
</span></span><span class="line"><span class="cl">find  / -size -30M              # 查找系统中大小小于30M的文件
</span></span></code></pre></div><h2 id="按时间来查找文件">按时间来查找文件</h2>
<p>Linux 会存储下面的时间：</p>
<ul>
<li>Access time 上一次文件读或者写的时间</li>
<li>Modifica time 上一次文件被修改的时间</li>
<li>Change time 上一次文件 <code>inode meta</code> 信息被修改的时间</li>
</ul>
<p>在按照时间查找时，可以使用 <code>-atime</code>， <code>-mtime</code> 或者 <code>-ctime</code>，和之前 <code>size</code>参数一样可以使用 <code>+</code> 或者 <code>-</code>时间范围，下图表示<code>find</code>的时间轴。<code>+</code>表示超过多少天，<code>-</code>表示多少天以内。</p>
<p>此外，也可以换成<code>-amin</code>， <code>-mmin</code> 或者 <code>-cmin</code>参数，单位是分钟。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210729151915.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210729151915.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">find / -mtime 1          # 寻找修改时间超过一天的文件
</span></span><span class="line"><span class="cl">find / -atime -1         # 寻找在一天时间内被访问的文件
</span></span><span class="line"><span class="cl">find / -ctime +3         # 寻找 meta 信息被修改的时间超过 3 天的文件
</span></span></code></pre></div><h2 id="reference">Reference</h2>
<ol>
<li>
<p><a href="http://c.biancheng.net/view/779.html">http://c.biancheng.net/view/779.html</a></p>
</li>
<li>
<p><a href="https://einverne.github.io/post/2018/02/find-command.html#%E6%89%B9%E9%87%8F%E5%88%A0%E9%99%A4%E6%97%B6%E9%97%B4%E8%B6%85%E8%BF%87-1-%E5%A4%A9%E7%9A%84%E6%96%87%E4%BB%B6">https://einverne.github.io/post/2018/02/find-command.html#%E6%89%B9%E9%87%8F%E5%88%A0%E9%99%A4%E6%97%B6%E9%97%B4%E8%B6%85%E8%BF%87-1-%E5%A4%A9%E7%9A%84%E6%96%87%E4%BB%B6</a></p>
</li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>在 QEMU 上运行 64 位和 32 位 RISC-V-Linux</title>
      <link>https://lifeislife.cn/posts/qemu%E4%B8%8A%E8%BF%90%E8%A1%8C64%E4%BD%8D%E5%92%8C32%E4%BD%8Drisc-v-linux/</link>
      <pubDate>Wed, 28 Jul 2021 13:47:56 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E4%B8%8A%E8%BF%90%E8%A1%8C64%E4%BD%8D%E5%92%8C32%E4%BD%8Drisc-v-linux/</guid>
      <description>&lt;h2 id=&#34;制作交叉工具链-riscv-gnu-toolchain&#34;&gt;制作交叉工具链 riscv-gnu-toolchain&lt;/h2&gt;
&lt;h3 id=&#34;下载源码&#34;&gt;下载源码&lt;/h3&gt;
&lt;p&gt;这个仓库是我遇到的最难下载的一个仓库了，公司网慢和虚拟机性能差都脱不了干系。估计下载了五小时都不止，刚开始还指望一个命令所有子模块都下载完的，结果愣是等了半天中断了。试了两次后放弃了。如果各位看官能一次完成，那您是福大。&lt;/p&gt;
&lt;p&gt;国内的码云平台有个&lt;a href=&#34;https://gitee.com/organizations/mirrors/projects&#34;&gt;Gitee 极速下载&lt;/a&gt;项目，上面有 GitHub 的一些常用开源项目的镜像，可供加速下载。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# riscv-gnu-toolchain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gitee&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;toolchain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下载时问题出现了，如果下载子模块仍然会卡住，如果不加&lt;code&gt;--recursive&lt;/code&gt;就只能下载主体内容，子模块都没有。（&lt;strong&gt;以下内容为第一安装时的方法，后续又找到了&lt;a href=&#34;&#34;&gt;git clone 快速下载子模块&lt;/a&gt;的方法&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;开始下载时不加&lt;code&gt;--recursive&lt;/code&gt;参数，只下载&lt;code&gt;riscv-gnu-toolchain&lt;/code&gt;的主体内容，然后进入到&lt;code&gt;riscv-gnu-toolchain&lt;/code&gt;文件夹下，手动下载子模块的内容。&lt;/p&gt;
&lt;p&gt;当下完&lt;code&gt;riscv-binutils&lt;/code&gt;继续下载&lt;code&gt;riscv-gdb&lt;/code&gt;时发现这两个项目是同一个项目，只是不同的分支。但是码云上并没有区分，但是我也没找到在码云上的对应分支。只能用油猴脚本了。&lt;/p&gt;
&lt;p&gt;如果你有油猴插件可以去&lt;a href=&#34;https://greasyfork.org/zh-CN&#34;&gt;greasyfork&lt;/a&gt;搜索安装&lt;strong&gt;GitHub 镜像访问，加速下载&lt;/strong&gt;这个脚本，刷新 GitHub 仓库界面就会多出几个镜像地址，一般下载都会快好几倍。如果不用油猴插件的可以用我复制好的链接。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728155417.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728155417.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# riscv-binutils
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://gitee.com/mirrors/riscv-binutils-gdb.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# riscv-gcc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://gitee.com/mirrors/riscv-gcc.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# riscv-dejagnu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://gitee.com/mirrors/riscv-dejagnu.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# riscv-glibc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://gitee.com/mirrors/riscv-glibc.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# riscv-newlib
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://gitee.com/mirrors/riscv-newlib.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# riscv-gdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone --depth=1 https://hub.fastgit.org/riscv/riscv-binutils-gdb.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;编译-riscv-gnu-toolchain&#34;&gt;编译 riscv-gnu-toolchain&lt;/h3&gt;
&lt;p&gt;提前安装如下软件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;sudo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;apt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;install&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;autoconf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;automake&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;autotools&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dev&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;curl&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;python3&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libmpc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dev&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libmpfr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dev&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libgmp&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dev&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gawk&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;essential&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bison&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flex&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;texinfo&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gperf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libtool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;patchutils&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;zlib1g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dev&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;libexpat&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dev&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不听老人言，吃亏在眼前呀，本以为这是可选项，很多库都安装了，就没有操作这一步，结果就是编译半天结果还错了。如果报&lt;code&gt;make 错误 127&lt;/code&gt;，那就老老实实把前置的这些库都装上。&lt;/p&gt;
&lt;p&gt;建立&lt;code&gt;riscv-gnu-toolchain&lt;/code&gt;安装目录&lt;code&gt;/opt/riscv64&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./configure --prefix=/opt/riscv64 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo make linux -j8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;导出安装路径&#34;&gt;导出安装路径&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;$PATH:/opt/riscv64/bin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;出现一下信息表示安装成功。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Using&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;built&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;specs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;COLLECT_GCC&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unknown&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linux&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gcc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;COLLECT_LTO_WRAPPER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libexec&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gcc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unknown&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linux&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;10.2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lto&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wrapper&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Target&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;riscv64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unknown&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linux&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Configured&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;home&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dominic&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linux&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;toolchain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gcc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unknown&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linux&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;prefix&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv64&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sysroot&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;opt&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv64&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sysroot&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zlib&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shared&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tls&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;enable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;languages&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fortran&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libmudflap&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libssp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libquadmath&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;libsanitizer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;nls&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bootstrap&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=.././&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gcc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;disable&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;multilib&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;abi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lp64d&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arch&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rv64imafdc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tune&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rocket&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;CFLAGS_FOR_TARGET=-O2   -mcmodel=medlow&amp;#39;&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;CXXFLAGS_FOR_TARGET=-O2   -mcmodel=medlow&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ne&#34;&gt;Thread&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;model&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;posix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Supported&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LTO&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;compression&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;algorithms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;zlib&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;gcc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;10.2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GCC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;制作内核&#34;&gt;制作内核&lt;/h2&gt;
&lt;h3 id=&#34;下载-linux-内核&#34;&gt;下载 Linux 内核&lt;/h3&gt;
&lt;p&gt;makefile&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="制作交叉工具链-riscv-gnu-toolchain">制作交叉工具链 riscv-gnu-toolchain</h2>
<h3 id="下载源码">下载源码</h3>
<p>这个仓库是我遇到的最难下载的一个仓库了，公司网慢和虚拟机性能差都脱不了干系。估计下载了五小时都不止，刚开始还指望一个命令所有子模块都下载完的，结果愣是等了半天中断了。试了两次后放弃了。如果各位看官能一次完成，那您是福大。</p>
<p>国内的码云平台有个<a href="https://gitee.com/organizations/mirrors/projects">Gitee 极速下载</a>项目，上面有 GitHub 的一些常用开源项目的镜像，可供加速下载。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># riscv-gnu-toolchain</span>
</span></span><span class="line"><span class="cl"><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">gitee</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">mirrors</span><span class="o">/</span><span class="n">riscv</span><span class="o">-</span><span class="n">gnu</span><span class="o">-</span><span class="n">toolchain</span><span class="o">.</span><span class="n">git</span>
</span></span></code></pre></div><p>下载时问题出现了，如果下载子模块仍然会卡住，如果不加<code>--recursive</code>就只能下载主体内容，子模块都没有。（<strong>以下内容为第一安装时的方法，后续又找到了<a href="">git clone 快速下载子模块</a>的方法</strong>）</p>
<p>开始下载时不加<code>--recursive</code>参数，只下载<code>riscv-gnu-toolchain</code>的主体内容，然后进入到<code>riscv-gnu-toolchain</code>文件夹下，手动下载子模块的内容。</p>
<p>当下完<code>riscv-binutils</code>继续下载<code>riscv-gdb</code>时发现这两个项目是同一个项目，只是不同的分支。但是码云上并没有区分，但是我也没找到在码云上的对应分支。只能用油猴脚本了。</p>
<p>如果你有油猴插件可以去<a href="https://greasyfork.org/zh-CN">greasyfork</a>搜索安装<strong>GitHub 镜像访问，加速下载</strong>这个脚本，刷新 GitHub 仓库界面就会多出几个镜像地址，一般下载都会快好几倍。如果不用油猴插件的可以用我复制好的链接。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728155417.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728155417.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># riscv-binutils
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-binutils-gdb.git
</span></span><span class="line"><span class="cl"># riscv-gcc
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-gcc.git
</span></span><span class="line"><span class="cl"># riscv-dejagnu
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-dejagnu.git
</span></span><span class="line"><span class="cl"># riscv-glibc
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-glibc.git
</span></span><span class="line"><span class="cl"># riscv-newlib
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-newlib.git
</span></span><span class="line"><span class="cl"># riscv-gdb
</span></span><span class="line"><span class="cl">git clone --depth=1 https://hub.fastgit.org/riscv/riscv-binutils-gdb.git
</span></span></code></pre></div><h3 id="编译-riscv-gnu-toolchain">编译 riscv-gnu-toolchain</h3>
<p>提前安装如下软件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">autoconf</span> <span class="n">automake</span> <span class="n">autotools</span><span class="o">-</span><span class="n">dev</span> <span class="n">curl</span> <span class="n">python3</span> <span class="n">libmpc</span><span class="o">-</span><span class="n">dev</span> <span class="n">libmpfr</span><span class="o">-</span><span class="n">dev</span> <span class="n">libgmp</span><span class="o">-</span><span class="n">dev</span> <span class="n">gawk</span> <span class="n">build</span><span class="o">-</span><span class="n">essential</span> <span class="n">bison</span> <span class="n">flex</span> <span class="n">texinfo</span> <span class="n">gperf</span> <span class="n">libtool</span> <span class="n">patchutils</span> <span class="n">bc</span> <span class="n">zlib1g</span><span class="o">-</span><span class="n">dev</span> <span class="n">libexpat</span><span class="o">-</span><span class="n">dev</span>
</span></span></code></pre></div><p>不听老人言，吃亏在眼前呀，本以为这是可选项，很多库都安装了，就没有操作这一步，结果就是编译半天结果还错了。如果报<code>make 错误 127</code>，那就老老实实把前置的这些库都装上。</p>
<p>建立<code>riscv-gnu-toolchain</code>安装目录<code>/opt/riscv64</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">./configure --prefix=/opt/riscv64 
</span></span><span class="line"><span class="cl">sudo make linux -j8
</span></span></code></pre></div><h3 id="导出安装路径">导出安装路径</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="k">export</span> <span class="n">PATH</span><span class="o">=</span><span class="s2">&#34;$PATH:/opt/riscv64/bin&#34;</span>
</span></span></code></pre></div><p>出现一下信息表示安装成功。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">Using</span> <span class="n">built</span><span class="o">-</span><span class="ow">in</span> <span class="n">specs</span><span class="o">.</span>
</span></span><span class="line"><span class="cl"><span class="n">COLLECT_GCC</span><span class="o">=</span><span class="n">riscv64</span><span class="o">-</span><span class="n">unknown</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">gnu</span><span class="o">-</span><span class="n">gcc</span>
</span></span><span class="line"><span class="cl"><span class="n">COLLECT_LTO_WRAPPER</span><span class="o">=/</span><span class="n">opt</span><span class="o">/</span><span class="n">riscv64</span><span class="o">/</span><span class="n">libexec</span><span class="o">/</span><span class="n">gcc</span><span class="o">/</span><span class="n">riscv64</span><span class="o">-</span><span class="n">unknown</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">gnu</span><span class="o">/</span><span class="mf">10.2</span><span class="o">.</span><span class="mi">0</span><span class="o">/</span><span class="n">lto</span><span class="o">-</span><span class="n">wrapper</span>
</span></span><span class="line"><span class="cl"><span class="n">Target</span><span class="p">:</span> <span class="n">riscv64</span><span class="o">-</span><span class="n">unknown</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">gnu</span>
</span></span><span class="line"><span class="cl"><span class="n">Configured</span> <span class="n">with</span><span class="p">:</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">dominic</span><span class="o">/</span><span class="n">riscv64</span><span class="o">-</span><span class="n">linux</span><span class="o">/</span><span class="n">riscv</span><span class="o">-</span><span class="n">gnu</span><span class="o">-</span><span class="n">toolchain</span><span class="o">/</span><span class="n">riscv</span><span class="o">-</span><span class="n">gcc</span><span class="o">/</span><span class="n">configure</span> <span class="o">--</span><span class="n">target</span><span class="o">=</span><span class="n">riscv64</span><span class="o">-</span><span class="n">unknown</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">gnu</span> <span class="o">--</span><span class="n">prefix</span><span class="o">=/</span><span class="n">opt</span><span class="o">/</span><span class="n">riscv64</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">sysroot</span><span class="o">=/</span><span class="n">opt</span><span class="o">/</span><span class="n">riscv64</span><span class="o">/</span><span class="n">sysroot</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">system</span><span class="o">-</span><span class="n">zlib</span> <span class="o">--</span><span class="n">enable</span><span class="o">-</span><span class="n">shared</span> <span class="o">--</span><span class="n">enable</span><span class="o">-</span><span class="n">tls</span> <span class="o">--</span><span class="n">enable</span><span class="o">-</span><span class="n">languages</span><span class="o">=</span><span class="n">c</span><span class="p">,</span><span class="n">c</span><span class="o">++</span><span class="p">,</span><span class="n">fortran</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">libmudflap</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">libssp</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">libquadmath</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">libsanitizer</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">nls</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">bootstrap</span> <span class="o">--</span><span class="n">src</span><span class="o">=.././</span><span class="n">riscv</span><span class="o">-</span><span class="n">gcc</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">multilib</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">abi</span><span class="o">=</span><span class="n">lp64d</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">arch</span><span class="o">=</span><span class="n">rv64imafdc</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">tune</span><span class="o">=</span><span class="n">rocket</span> <span class="s1">&#39;CFLAGS_FOR_TARGET=-O2   -mcmodel=medlow&#39;</span> <span class="s1">&#39;CXXFLAGS_FOR_TARGET=-O2   -mcmodel=medlow&#39;</span>
</span></span><span class="line"><span class="cl"><span class="ne">Thread</span> <span class="n">model</span><span class="p">:</span> <span class="n">posix</span>
</span></span><span class="line"><span class="cl"><span class="n">Supported</span> <span class="n">LTO</span> <span class="n">compression</span> <span class="n">algorithms</span><span class="p">:</span> <span class="n">zlib</span>
</span></span><span class="line"><span class="cl"><span class="n">gcc</span> <span class="n">version</span> <span class="mf">10.2</span><span class="o">.</span><span class="mi">0</span> <span class="p">(</span><span class="n">GCC</span><span class="p">)</span> 
</span></span></code></pre></div><h2 id="制作内核">制作内核</h2>
<h3 id="下载-linux-内核">下载 Linux 内核</h3>
<p>makefile</p>
]]></content:encoded>
    </item>
    <item>
      <title>每天学命令-df/du查看磁盘剩余空间</title>
      <link>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-df-du%E6%9F%A5%E7%9C%8B%E7%A3%81%E7%9B%98%E5%89%A9%E4%BD%99%E7%A9%BA%E9%97%B4/</link>
      <pubDate>Wed, 28 Jul 2021 10:13:58 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E6%AF%8F%E5%A4%A9%E5%AD%A6%E5%91%BD%E4%BB%A4-df-du%E6%9F%A5%E7%9C%8B%E7%A3%81%E7%9B%98%E5%89%A9%E4%BD%99%E7%A9%BA%E9%97%B4/</guid>
      <description>&lt;p&gt;&lt;code&gt;df&lt;/code&gt;全称&lt;code&gt;disk filesystem&lt;/code&gt; ，以磁盘分区为单位查看文件系统，可以查看磁盘文件占用空间，磁盘剩余空间等信息。&lt;/p&gt;
&lt;h2 id=&#34;命令格式&#34;&gt;命令格式&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;df [] []
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;可选参数&#34;&gt;可选参数&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-a      全部文件系统列表
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-h      方便阅读方式显示
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-H      等于“-h”，但是计算式，1K=1000，而不是 1K=1024
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-i      显示 inode 信息
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-k      区块为 1024 字节
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-l      只显示本地文件系统
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-m      区块为 1048576 字节
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--no-sync 忽略 sync 命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-P      输出格式为 POSIX
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--sync  在取得磁盘信息前，先执行 sync 命令
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-T      文件系统类型
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用实例&#34;&gt;使用实例&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;df -T&lt;/code&gt;显示包含文件系统，类型，可用大小，已用大小，挂载点等信息。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~$ df -T
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;文件系统       类型         1K-块      已用      可用 已用% 挂载点
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;udev           devtmpfs   1985056         0   1985056    0% /dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs          tmpfs       403036      1304    401732    1% /run
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda5      ext4      50824704  20826256  27386992   44% /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs          tmpfs      2015172         0   2015172    0% /dev/shm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs          tmpfs         5120         4      5116    1% /run/lock
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs          tmpfs      2015172         0   2015172    0% /sys/fs/cgroup
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/loop0     squashfs     56832     56832         0  100% /snap/core18/1988
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/loop1     squashfs     56832     56832         0  100% /snap/core18/2074
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;&lt;code&gt;du&lt;/code&gt;全称&lt;code&gt;disk usage&lt;/code&gt;可以查看文件，文件夹占用情况。&lt;/p&gt;
&lt;h2 id=&#34;命令格式-1&#34;&gt;命令格式&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;du [opt] [filename]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;可选参数-1&#34;&gt;可选参数&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-a或-all                    #显示目录中个别文件的大小。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-b或-bytes                  #显示目录或文件大小时，以byte为单位。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-c或--total                 #除了显示个别目录或文件的大小外，同时也显示所有目录或文件的总和。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-D或--dereference-args      #显示指定符号连接的源文件大小。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-h或--human-readable        #以K，M，G为单位，提高信息的可读性。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-H或--si                    #与-h参数相同，但是K，M，G是以1000为换算单位。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-k或--kilobytes             #以1024 bytes为单位。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-l或--count-links           #重复计算硬件连接的文件。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-L&amp;lt;符号连接&amp;gt;或-
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-dereference&amp;lt;符号连接&amp;gt;          #显示选项中所指定符号连接的源文件大小。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-m或--megabytes                 #以1MB为单位。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-s或--summarize                 #仅显示总计。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-S或--separate-dirs             #显示个别目录的大小时，并不含其子目录的大小。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-x或--one-file-xystem           #以一开始处理时的文件系统为准，若遇上其它不同的文件系统目录则略过。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-X&amp;lt;文件&amp;gt;或--exclude-from=&amp;lt;文件&amp;gt;  #在&amp;lt;文件&amp;gt;指定目录或文件。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--exclude=&amp;lt;目录或文件&amp;gt;           #略过指定的目录或文件。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--max-depth=&amp;lt;目录层数&amp;gt;           #超过指定层数的目录后，予以忽略。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--help          #显示帮助。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;--version       #显示版本信息
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用实例-1&#34;&gt;使用实例&lt;/h2&gt;
&lt;p&gt;查看当前目录使用情况&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~/learning-linux$ du
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;56 ./.git/hooks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 ./.git/logs/refs/heads
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 ./.git/logs/refs/remotes/origin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12 ./.git/logs/refs/remotes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;24 ./.git/logs/refs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;32 ./.git/logs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 ./.git/info
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以易读的方式查看使用情况&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~/learning-linux$ du -h
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;56K ./.git/hooks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8.0K ./.git/logs/refs/heads
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8.0K ./.git/logs/refs/remotes/origin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12K ./.git/logs/refs/remotes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;24K ./.git/logs/refs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;32K ./.git/logs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8.0K ./.git/info
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;只输出当前目录占用总空间，同上&lt;code&gt;-h&lt;/code&gt;命令就是以人读的方式（加上了数据单位）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~/learning-linux$ du -hs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;264K .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看当前目录及其指定深度目录的大小&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;不深入子目录，就是当前文件夹所占用大小
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~/learning-linux$ du -h --max-depth=0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;264K .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;深入一层
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~/learning-linux$ du -h --max-depth=2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;56K ./.git/hooks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;32K ./.git/logs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8.0K ./.git/info
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;28K ./.git/objects
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4.0K ./.git/branches
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;28K ./.git/refs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;180K ./.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;24K ./helloworld/c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;44K ./helloworld/shell
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;72K ./helloworld
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;264K .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;忽略&lt;code&gt;helloworld&lt;/code&gt;这个文件夹&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dominic@hanhan:~/learning-linux$ du --exclude=helloworld
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;56 ./.git/hooks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 ./.git/logs/refs/heads
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 ./.git/logs/refs/remotes/origin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12 ./.git/logs/refs/remotes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;24 ./.git/logs/refs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;32 ./.git/logs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 ./.git/info
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4 ./.git/objects/info
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;20 ./.git/objects/pack
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;28 ./.git/objects
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4 ./.git/branches
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 ./.git/refs/heads
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4 ./.git/refs/tags
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;8 ./.git/refs/remotes/origin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12 ./.git/refs/remotes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;28 ./.git/refs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;180 ./.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;192 .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;refernece&#34;&gt;Refernece&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://einverne.github.io/post/2018/03/du-find-out-which-fold-take-space.html&#34;&gt;https://einverne.github.io/post/2018/03/du-find-out-which-fold-take-space.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.runoob.com/linux/linux-comm-du.html&#34;&gt;https://www.runoob.com/linux/linux-comm-du.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
      <content:encoded><![CDATA[<p><code>df</code>全称<code>disk filesystem</code> ，以磁盘分区为单位查看文件系统，可以查看磁盘文件占用空间，磁盘剩余空间等信息。</p>
<h2 id="命令格式">命令格式</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">df [] []
</span></span></code></pre></div><h2 id="可选参数">可选参数</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">-a      全部文件系统列表
</span></span><span class="line"><span class="cl">-h      方便阅读方式显示
</span></span><span class="line"><span class="cl">-H      等于“-h”，但是计算式，1K=1000，而不是 1K=1024
</span></span><span class="line"><span class="cl">-i      显示 inode 信息
</span></span><span class="line"><span class="cl">-k      区块为 1024 字节
</span></span><span class="line"><span class="cl">-l      只显示本地文件系统
</span></span><span class="line"><span class="cl">-m      区块为 1048576 字节
</span></span><span class="line"><span class="cl">--no-sync 忽略 sync 命令
</span></span><span class="line"><span class="cl">-P      输出格式为 POSIX
</span></span><span class="line"><span class="cl">--sync  在取得磁盘信息前，先执行 sync 命令
</span></span><span class="line"><span class="cl">-T      文件系统类型
</span></span></code></pre></div><h2 id="使用实例">使用实例</h2>
<p><code>df -T</code>显示包含文件系统，类型，可用大小，已用大小，挂载点等信息。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:~$ df -T
</span></span><span class="line"><span class="cl">文件系统       类型         1K-块      已用      可用 已用% 挂载点
</span></span><span class="line"><span class="cl">udev           devtmpfs   1985056         0   1985056    0% /dev
</span></span><span class="line"><span class="cl">tmpfs          tmpfs       403036      1304    401732    1% /run
</span></span><span class="line"><span class="cl">/dev/sda5      ext4      50824704  20826256  27386992   44% /
</span></span><span class="line"><span class="cl">tmpfs          tmpfs      2015172         0   2015172    0% /dev/shm
</span></span><span class="line"><span class="cl">tmpfs          tmpfs         5120         4      5116    1% /run/lock
</span></span><span class="line"><span class="cl">tmpfs          tmpfs      2015172         0   2015172    0% /sys/fs/cgroup
</span></span><span class="line"><span class="cl">/dev/loop0     squashfs     56832     56832         0  100% /snap/core18/1988
</span></span><span class="line"><span class="cl">/dev/loop1     squashfs     56832     56832         0  100% /snap/core18/2074
</span></span></code></pre></div><hr>
<p><code>du</code>全称<code>disk usage</code>可以查看文件，文件夹占用情况。</p>
<h2 id="命令格式-1">命令格式</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">du [opt] [filename]
</span></span></code></pre></div><h2 id="可选参数-1">可选参数</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">-a或-all                    #显示目录中个别文件的大小。
</span></span><span class="line"><span class="cl">-b或-bytes                  #显示目录或文件大小时，以byte为单位。
</span></span><span class="line"><span class="cl">-c或--total                 #除了显示个别目录或文件的大小外，同时也显示所有目录或文件的总和。
</span></span><span class="line"><span class="cl">-D或--dereference-args      #显示指定符号连接的源文件大小。
</span></span><span class="line"><span class="cl">-h或--human-readable        #以K，M，G为单位，提高信息的可读性。
</span></span><span class="line"><span class="cl">-H或--si                    #与-h参数相同，但是K，M，G是以1000为换算单位。
</span></span><span class="line"><span class="cl">-k或--kilobytes             #以1024 bytes为单位。
</span></span><span class="line"><span class="cl">-l或--count-links           #重复计算硬件连接的文件。
</span></span><span class="line"><span class="cl">-L&lt;符号连接&gt;或-
</span></span><span class="line"><span class="cl">-dereference&lt;符号连接&gt;          #显示选项中所指定符号连接的源文件大小。
</span></span><span class="line"><span class="cl">-m或--megabytes                 #以1MB为单位。
</span></span><span class="line"><span class="cl">-s或--summarize                 #仅显示总计。
</span></span><span class="line"><span class="cl">-S或--separate-dirs             #显示个别目录的大小时，并不含其子目录的大小。
</span></span><span class="line"><span class="cl">-x或--one-file-xystem           #以一开始处理时的文件系统为准，若遇上其它不同的文件系统目录则略过。
</span></span><span class="line"><span class="cl">-X&lt;文件&gt;或--exclude-from=&lt;文件&gt;  #在&lt;文件&gt;指定目录或文件。
</span></span><span class="line"><span class="cl">--exclude=&lt;目录或文件&gt;           #略过指定的目录或文件。
</span></span><span class="line"><span class="cl">--max-depth=&lt;目录层数&gt;           #超过指定层数的目录后，予以忽略。
</span></span><span class="line"><span class="cl">--help          #显示帮助。
</span></span><span class="line"><span class="cl">--version       #显示版本信息
</span></span></code></pre></div><h2 id="使用实例-1">使用实例</h2>
<p>查看当前目录使用情况</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:~/learning-linux$ du
</span></span><span class="line"><span class="cl">56 ./.git/hooks
</span></span><span class="line"><span class="cl">8 ./.git/logs/refs/heads
</span></span><span class="line"><span class="cl">8 ./.git/logs/refs/remotes/origin
</span></span><span class="line"><span class="cl">12 ./.git/logs/refs/remotes
</span></span><span class="line"><span class="cl">24 ./.git/logs/refs
</span></span><span class="line"><span class="cl">32 ./.git/logs
</span></span><span class="line"><span class="cl">8 ./.git/info
</span></span></code></pre></div><p>以易读的方式查看使用情况</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:~/learning-linux$ du -h
</span></span><span class="line"><span class="cl">56K ./.git/hooks
</span></span><span class="line"><span class="cl">8.0K ./.git/logs/refs/heads
</span></span><span class="line"><span class="cl">8.0K ./.git/logs/refs/remotes/origin
</span></span><span class="line"><span class="cl">12K ./.git/logs/refs/remotes
</span></span><span class="line"><span class="cl">24K ./.git/logs/refs
</span></span><span class="line"><span class="cl">32K ./.git/logs
</span></span><span class="line"><span class="cl">8.0K ./.git/info
</span></span></code></pre></div><p>只输出当前目录占用总空间，同上<code>-h</code>命令就是以人读的方式（加上了数据单位）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:~/learning-linux$ du -hs
</span></span><span class="line"><span class="cl">264K .
</span></span></code></pre></div><p>查看当前目录及其指定深度目录的大小</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">不深入子目录，就是当前文件夹所占用大小
</span></span><span class="line"><span class="cl">dominic@hanhan:~/learning-linux$ du -h --max-depth=0
</span></span><span class="line"><span class="cl">264K .
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">深入一层
</span></span><span class="line"><span class="cl">dominic@hanhan:~/learning-linux$ du -h --max-depth=2
</span></span><span class="line"><span class="cl">56K ./.git/hooks
</span></span><span class="line"><span class="cl">32K ./.git/logs
</span></span><span class="line"><span class="cl">8.0K ./.git/info
</span></span><span class="line"><span class="cl">28K ./.git/objects
</span></span><span class="line"><span class="cl">4.0K ./.git/branches
</span></span><span class="line"><span class="cl">28K ./.git/refs
</span></span><span class="line"><span class="cl">180K ./.git
</span></span><span class="line"><span class="cl">24K ./helloworld/c
</span></span><span class="line"><span class="cl">44K ./helloworld/shell
</span></span><span class="line"><span class="cl">72K ./helloworld
</span></span><span class="line"><span class="cl">264K .
</span></span></code></pre></div><p>忽略<code>helloworld</code>这个文件夹</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">dominic@hanhan:~/learning-linux$ du --exclude=helloworld
</span></span><span class="line"><span class="cl">56 ./.git/hooks
</span></span><span class="line"><span class="cl">8 ./.git/logs/refs/heads
</span></span><span class="line"><span class="cl">8 ./.git/logs/refs/remotes/origin
</span></span><span class="line"><span class="cl">12 ./.git/logs/refs/remotes
</span></span><span class="line"><span class="cl">24 ./.git/logs/refs
</span></span><span class="line"><span class="cl">32 ./.git/logs
</span></span><span class="line"><span class="cl">8 ./.git/info
</span></span><span class="line"><span class="cl">4 ./.git/objects/info
</span></span><span class="line"><span class="cl">20 ./.git/objects/pack
</span></span><span class="line"><span class="cl">28 ./.git/objects
</span></span><span class="line"><span class="cl">4 ./.git/branches
</span></span><span class="line"><span class="cl">8 ./.git/refs/heads
</span></span><span class="line"><span class="cl">4 ./.git/refs/tags
</span></span><span class="line"><span class="cl">8 ./.git/refs/remotes/origin
</span></span><span class="line"><span class="cl">12 ./.git/refs/remotes
</span></span><span class="line"><span class="cl">28 ./.git/refs
</span></span><span class="line"><span class="cl">180 ./.git
</span></span><span class="line"><span class="cl">192 .
</span></span></code></pre></div><h2 id="refernece">Refernece</h2>
<ol>
<li><a href="https://einverne.github.io/post/2018/03/du-find-out-which-fold-take-space.html">https://einverne.github.io/post/2018/03/du-find-out-which-fold-take-space.html</a></li>
<li><a href="https://www.runoob.com/linux/linux-comm-du.html">https://www.runoob.com/linux/linux-comm-du.html</a></li>
</ol>
]]></content:encoded>
    </item>
    <item>
      <title>Linux(Ubuntu) 环境下安装 Qt</title>
      <link>https://lifeislife.cn/posts/linux-ubuntu-%E7%8E%AF%E5%A2%83%E4%B8%8B%E5%AE%89%E8%A3%85qt/</link>
      <pubDate>Tue, 27 Jul 2021 16:34:50 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux-ubuntu-%E7%8E%AF%E5%A2%83%E4%B8%8B%E5%AE%89%E8%A3%85qt/</guid>
      <description>&lt;p&gt;真蠢，之前费那么大劲，只要一句命令就完事了&lt;/p&gt;
&lt;h2 id=&#34;下载安装&#34;&gt;下载安装&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install qtcreator
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是在用命令行构建 project 时可能会报错&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qmake -project
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;could not find a Qt installation of &amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时候需要&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install qt5-default 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;好了可以愉快玩耍了。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;瞎折腾&lt;/p&gt;
&lt;h2 id=&#34;下载-qt&#34;&gt;下载 Qt&lt;/h2&gt;
&lt;p&gt;从 Qt5.15.0 起，对于开源用户，Qt 官方不再提供独立安装文件，且不再有 bug 修复版本（比如 Qt5.15.1），如果从官网下载，需要自己编译。虽然想试试编译，但是虚拟机刚开始开的空间太小了，还是另寻他法吧。以后有机会再来编译试试新功能。若读者有兴趣可以从&lt;a href=&#34;https://download.qt.io/archive/qt/&#34;&gt;官网&lt;/a&gt;下载源码并编译。或者参考&lt;a href=&#34;https://wiki.qt.io/Building_Qt_5_from_Git#Getting_the_source_code&#34;&gt;官方的编译教程&lt;/a&gt;，从 GitHub 上下载。&lt;/p&gt;
&lt;p&gt;国内有一些镜像站，提供 qt 镜像下载：
清华大学：&lt;a href=&#34;https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/&#34;&gt;https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/&lt;/a&gt;
中国科学技术大学：&lt;a href=&#34;http://mirrors.ustc.edu.cn/qtproject/&#34;&gt;http://mirrors.ustc.edu.cn/qtproject/&lt;/a&gt;
北京理工大学：&lt;a href=&#34;https://mirrors.cnnic.cn/qt/&#34;&gt;https://mirrors.cnnic.cn/qt/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以清华大学的镜像为例，找到&lt;code&gt;archive/qt/5.14/5.14.0/qt-opensource-linux-x64-5.14.0.run&lt;/code&gt;，点击即可开始下载。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;qt 5.15 已经不提供安装包，想要最新版本，只能下 5.14，但是 5.14.2 下载没资源，下不动，如果遇到下不动的情况换一个版本吧&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;安装-qt&#34;&gt;安装 Qt&lt;/h2&gt;
&lt;p&gt;下载的&lt;code&gt;.run&lt;/code&gt;文件双击是无法安装的，因为它还没有可执行的权限，需要我们赋给它执行权限，打开终端进入安装包的目录。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chmod +x filename.run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;chmod&lt;/code&gt;命令是控制用户对文件的权限修改的命令，&lt;code&gt;x&lt;/code&gt;是可执行权限的参数。
执行以上命令后就可以直接双击安装了。&lt;/p&gt;
&lt;p&gt;网上一些教程可以跳过登录，我没找到跳过按钮，需要注册一个账号才能继续安装。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728092743.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728092743.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;安装目录一般选择在&lt;code&gt;/opt&lt;/code&gt;目录下


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728092813.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728092813.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;安装的附加组件最好都选择，以免后期使用再安装麻烦。Qt Creator 肯定要装的。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728093014.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728093014.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;安装依赖库&#34;&gt;安装依赖库&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install g++
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install libgl1-mesa-dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install libqt4-dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install build-essential # Build Essential，它是一个元软件包，可让您在Ubuntu中安装和使用c ++工具。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install qt5-default # 如果要将Qt 5用作默认的Qt Creator版本需要安装，否则会报 qmake: could not find a Qt installation of &amp;#39;&amp;#39;的错误
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用-qt-creator-创建第一个程序&#34;&gt;使用 Qt Creator 创建第一个程序&lt;/h2&gt;
&lt;h3 id=&#34;使用-qt-creator-创建&#34;&gt;使用 Qt Creator 创建&lt;/h3&gt;
&lt;p&gt;首先我们先创建一个不带窗口的 HelloWorld 程序，测试安装是否成功，打开 Qt Creator-文件 - 新建文件或项目，选择 Non-Qt Project-Plain C++ Application。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728102920.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728102920.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
接下来就设置项目名等，一直下一步。完成后就可以在编辑器看到如下


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728103424.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728103424.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;点击左下角运行按钮就可以得到如下：


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728103540.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728103540.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;再创建一个带窗口的 HelloWorld，在选择模板时选择 Application-Qt Widgets Application。一路点下一步就可以完成创建，运行后就可得到一个灰白的 HelloWorld 窗口。&lt;/p&gt;
&lt;h3 id=&#34;命令行编译第一个-qt-程序&#34;&gt;命令行编译第一个 Qt 程序&lt;/h3&gt;
&lt;p&gt;首先创建工作目录&lt;code&gt;HelloWorldQt&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir HelloWorld
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进入项目目录下，新建一个&lt;code&gt;main.cpp&lt;/code&gt;文件&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; HelloWorldQt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim main.cpp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑以下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;QApplication&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;QLabel&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;QWidget&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;QApplication&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;QLabel&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;lt;center&amp;gt;Welcome to my first Qt program&amp;lt;/center&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;setWindowTitle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;My First Qt Program&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;resize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;400&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;400&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;hello&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;show&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;建立 QtProject 文件&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qmake -project
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用&lt;code&gt;vim&lt;/code&gt;打开&lt;code&gt;HelloWorldQt.pro&lt;/code&gt;文件，添加以下内容&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;QT += gui widgets
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730095602.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730095602.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
运行&lt;code&gt;qmake&lt;/code&gt;，使项目 platform-specific，会得到一个&lt;code&gt;Makefile&lt;/code&gt;文件&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qmake HelloWorldQt.pro 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;make&lt;/code&gt;命令将&lt;code&gt;Makefile&lt;/code&gt;编译为可执行程序&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;➜  HelloWorldQt make
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;g++ -c -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS / 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-DQT_NO_DEBUG -DQT_WIDGETS_LIB /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-DQT_GUI_LIB -DQT_CORE_LIB -I. / 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-I. -isystem / 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/include/x86_64-linux-gnu/qt5 -isystem / 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/include/x86_64-linux-gnu/qt5/QtWidgets /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-isystem /usr/include/x86_64-linux-gnu/qt5/QtGui /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o main.o main.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;g++ -Wl,-O1 -o HelloWorldQt main.o  /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/lib/x86_64-linux-gnu/libQt5Widgets.so /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/lib/x86_64-linux-gnu/libQt5Gui.so / 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/lib/x86_64-linux-gnu/libQt5Core.so /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/lib/x86_64-linux-gnu/libGL.so -lpthread 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果一切顺利，执行可以得到如下&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./HelloWorldQt 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728112155.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728112155.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>真蠢，之前费那么大劲，只要一句命令就完事了</p>
<h2 id="下载安装">下载安装</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo apt install qtcreator
</span></span></code></pre></div><p>但是在用命令行构建 project 时可能会报错</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qmake -project
</span></span><span class="line"><span class="cl">could not find a Qt installation of &#39;&#39;
</span></span></code></pre></div><p>这时候需要</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo apt-get install qt5-default 
</span></span></code></pre></div><p>好了可以愉快玩耍了。</p>
<hr>
<p>瞎折腾</p>
<h2 id="下载-qt">下载 Qt</h2>
<p>从 Qt5.15.0 起，对于开源用户，Qt 官方不再提供独立安装文件，且不再有 bug 修复版本（比如 Qt5.15.1），如果从官网下载，需要自己编译。虽然想试试编译，但是虚拟机刚开始开的空间太小了，还是另寻他法吧。以后有机会再来编译试试新功能。若读者有兴趣可以从<a href="https://download.qt.io/archive/qt/">官网</a>下载源码并编译。或者参考<a href="https://wiki.qt.io/Building_Qt_5_from_Git#Getting_the_source_code">官方的编译教程</a>，从 GitHub 上下载。</p>
<p>国内有一些镜像站，提供 qt 镜像下载：
清华大学：<a href="https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/">https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/</a>
中国科学技术大学：<a href="http://mirrors.ustc.edu.cn/qtproject/">http://mirrors.ustc.edu.cn/qtproject/</a>
北京理工大学：<a href="https://mirrors.cnnic.cn/qt/">https://mirrors.cnnic.cn/qt/</a></p>
<p>以清华大学的镜像为例，找到<code>archive/qt/5.14/5.14.0/qt-opensource-linux-x64-5.14.0.run</code>，点击即可开始下载。</p>
<blockquote>
<p>qt 5.15 已经不提供安装包，想要最新版本，只能下 5.14，但是 5.14.2 下载没资源，下不动，如果遇到下不动的情况换一个版本吧</p>
</blockquote>
<h2 id="安装-qt">安装 Qt</h2>
<p>下载的<code>.run</code>文件双击是无法安装的，因为它还没有可执行的权限，需要我们赋给它执行权限，打开终端进入安装包的目录。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">chmod +x filename.run
</span></span></code></pre></div><p><code>chmod</code>命令是控制用户对文件的权限修改的命令，<code>x</code>是可执行权限的参数。
执行以上命令后就可以直接双击安装了。</p>
<p>网上一些教程可以跳过登录，我没找到跳过按钮，需要注册一个账号才能继续安装。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728092743.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728092743.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>安装目录一般选择在<code>/opt</code>目录下


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728092813.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728092813.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>安装的附加组件最好都选择，以免后期使用再安装麻烦。Qt Creator 肯定要装的。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728093014.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728093014.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="安装依赖库">安装依赖库</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt-get install g++
</span></span><span class="line"><span class="cl">apt-get install libgl1-mesa-dev
</span></span><span class="line"><span class="cl">apt-get install libqt4-dev
</span></span><span class="line"><span class="cl">apt-get install build-essential # Build Essential，它是一个元软件包，可让您在Ubuntu中安装和使用c ++工具。
</span></span><span class="line"><span class="cl">sudo apt install qt5-default # 如果要将Qt 5用作默认的Qt Creator版本需要安装，否则会报 qmake: could not find a Qt installation of &#39;&#39;的错误
</span></span></code></pre></div><h2 id="使用-qt-creator-创建第一个程序">使用 Qt Creator 创建第一个程序</h2>
<h3 id="使用-qt-creator-创建">使用 Qt Creator 创建</h3>
<p>首先我们先创建一个不带窗口的 HelloWorld 程序，测试安装是否成功，打开 Qt Creator-文件 - 新建文件或项目，选择 Non-Qt Project-Plain C++ Application。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728102920.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728102920.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>
接下来就设置项目名等，一直下一步。完成后就可以在编辑器看到如下


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728103424.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728103424.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>点击左下角运行按钮就可以得到如下：


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728103540.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728103540.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>再创建一个带窗口的 HelloWorld，在选择模板时选择 Application-Qt Widgets Application。一路点下一步就可以完成创建，运行后就可得到一个灰白的 HelloWorld 窗口。</p>
<h3 id="命令行编译第一个-qt-程序">命令行编译第一个 Qt 程序</h3>
<p>首先创建工作目录<code>HelloWorldQt</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">mkdir HelloWorld
</span></span></code></pre></div><p>进入项目目录下，新建一个<code>main.cpp</code>文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> HelloWorldQt
</span></span><span class="line"><span class="cl">vim main.cpp
</span></span></code></pre></div><p>编辑以下内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c++" data-lang="c++"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;QApplication&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;QLabel&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;QWidget&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[</span> <span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">QApplication</span> <span class="n">app</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">QLabel</span> <span class="n">hello</span><span class="p">(</span><span class="s">&#34;&lt;center&gt;Welcome to my first Qt program&lt;/center&gt;&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">hello</span><span class="p">.</span><span class="n">setWindowTitle</span><span class="p">(</span><span class="s">&#34;My First Qt Program&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">hello</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="mi">400</span><span class="p">,</span> <span class="mi">400</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">hello</span><span class="p">.</span><span class="n">show</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">app</span><span class="p">.</span><span class="n">exec</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>建立 QtProject 文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qmake -project
</span></span></code></pre></div><p>用<code>vim</code>打开<code>HelloWorldQt.pro</code>文件，添加以下内容</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">QT += gui widgets
</span></span></code></pre></div><p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730095602.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210730095602.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>
运行<code>qmake</code>，使项目 platform-specific，会得到一个<code>Makefile</code>文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qmake HelloWorldQt.pro 
</span></span></code></pre></div><p>使用<code>make</code>命令将<code>Makefile</code>编译为可执行程序</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">➜  HelloWorldQt make
</span></span><span class="line"><span class="cl">g++ -c -pipe -O2 -Wall -W -D_REENTRANT -fPIC -DQT_DEPRECATED_WARNINGS / 
</span></span><span class="line"><span class="cl">-DQT_NO_DEBUG -DQT_WIDGETS_LIB /
</span></span><span class="line"><span class="cl">-DQT_GUI_LIB -DQT_CORE_LIB -I. / 
</span></span><span class="line"><span class="cl">-I. -isystem / 
</span></span><span class="line"><span class="cl">/usr/include/x86_64-linux-gnu/qt5 -isystem / 
</span></span><span class="line"><span class="cl">/usr/include/x86_64-linux-gnu/qt5/QtWidgets /
</span></span><span class="line"><span class="cl">-isystem /usr/include/x86_64-linux-gnu/qt5/QtGui /
</span></span><span class="line"><span class="cl">-isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. /
</span></span><span class="line"><span class="cl">-I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o main.o main.cpp
</span></span><span class="line"><span class="cl">g++ -Wl,-O1 -o HelloWorldQt main.o  /
</span></span><span class="line"><span class="cl">/usr/lib/x86_64-linux-gnu/libQt5Widgets.so /
</span></span><span class="line"><span class="cl">/usr/lib/x86_64-linux-gnu/libQt5Gui.so / 
</span></span><span class="line"><span class="cl">/usr/lib/x86_64-linux-gnu/libQt5Core.so /
</span></span><span class="line"><span class="cl">/usr/lib/x86_64-linux-gnu/libGL.so -lpthread 
</span></span></code></pre></div><p>如果一切顺利，执行可以得到如下</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">./HelloWorldQt 
</span></span></code></pre></div><p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728112155.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210728112155.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>QEMU 文档</title>
      <link>https://lifeislife.cn/posts/qemu%E6%96%87%E6%A1%A3/</link>
      <pubDate>Tue, 27 Jul 2021 11:12:01 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E6%96%87%E6%A1%A3/</guid>
      <description>&lt;h1 id=&#34;调用文档&#34;&gt;调用文档&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;qemu-system-x86_64 [options] [disk_image] &lt;/code&gt;
&lt;code&gt;disk_image&lt;/code&gt;是 IDE 硬盘 0 的原始硬盘映像。某些目标不需要磁盘映像。&lt;/p&gt;
&lt;h2 id=&#34;标准参数-standard-options&#34;&gt;标准参数 Standard options&lt;/h2&gt;
&lt;h3 id=&#34;-h&#34;&gt;&lt;code&gt;-h&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能
显示帮助信息并退出&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子参数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用实例&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-riscv32 -h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-version&#34;&gt;&lt;code&gt;-version&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能
显示 qemu 版本信息并退出&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子参数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用实例&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-riscv32 -version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-machine-typenamepropvalue&#34;&gt;&lt;code&gt;-machine [type=]name[,prop=value[,...]]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能
通过名称选择模拟器。使用 &lt;code&gt;-machine help&lt;/code&gt; 可以查看可用的模拟器。
对于支持跨版本实时迁移兼容性的架构，每个版本都会引入一个新的版本化模拟器类型。例如，2.8.0 版本为 &lt;code&gt;x86_64/i686&lt;/code&gt; 架构引入了&lt;code&gt;“pc-i440fx-2.8”&lt;/code&gt;和&lt;code&gt;“pc-q35-2.8”&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子参数
为了允许用户从 QEMU 2.8.0 版实时迁移到 QEMU 2.9.0 版，2.9.0 版也必须支持&lt;code&gt;“pc-i440fx-2.8”&lt;/code&gt;和&lt;code&gt;“pc-q35-2.8”&lt;/code&gt;机器。为了允许用户在升级时实时迁移 VMs 跳过多个中间版本，QEMU 的新版本将支持多个以前版本的机器类型。
支持的机器属性有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;accel=accels1[:accels2[:...]]&lt;/code&gt;
This is used to enable an accelerator. Depending on the target architecture, kvm, xen, hax, hvf, nvmm, whpx or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vmport=on|off|auto&lt;/code&gt;
Enables emulation of VMWare IO port, for vmmouse etc. auto says to select the value based on accel. For accel=xen the default is off otherwise the default is on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dump-guest-core=on|off&lt;/code&gt;
Include guest memory in a core dump. The default is on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mem-merge=on|off&lt;/code&gt;
Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled by default).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aes-key-wrap=on|off&lt;/code&gt;
Enables or disables AES key wrapping support on s390-ccw hosts. This feature controls whether AES wrapping keys will be created to allow execution of AES cryptographic functions. The default is on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dea-key-wrap=on|off&lt;/code&gt;
Enables or disables DEA key wrapping support on s390-ccw hosts. This feature controls whether DEA wrapping keys will be created to allow execution of DEA cryptographic functions. The default is on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nvdimm=on|off&lt;/code&gt;
Enables or disables NVDIMM support. The default is off.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;memory-encryption=&lt;/code&gt;
Memory encryption object to use. The default is none.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hmat=on|off&lt;/code&gt;
Enables or disables ACPI Heterogeneous Memory Attribute Table (HMAT) support. The default is off.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;memory-backend=&#39;id&#39;&lt;/code&gt;
An alternative to legacy -mem-path and mem-prealloc options. Allows to use a memory backend as main RAM.
For example: &lt;code&gt;:: -object memory-backend-file,id=pc.ram,size=512M,mem-path=/hugetlbfs,prealloc=on,share=on -machine memory-backend=pc.ram -m 512M&lt;/code&gt;
Migration compatibility note: a) as backend id one shall use value of ‘default-ram-id’, advertised by machine type (available via query-machines QMP command), if migration to/from old QEMU (&amp;lt;5.0) is expected. b) for machine types 4.0 and older, user shall use x-use-canonical-path-for-ramblock-id=off backend option if migration to/from old QEMU (&amp;lt;5.0) is expected. For example: :: -object memory-backend-ram,id=pc.ram,size=512M,x-use-canonical-path-for-ramblock-id=off -machine memory-backend=pc.ram -m 512M&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用实例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-riscv32 -machine virt,mem-merge=on
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-cpu-model&#34;&gt;&lt;code&gt;-cpu model&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
选择 CPU 型号（&lt;code&gt;-cpu help&lt;/code&gt;显示帮助列表和附加功能的选项）&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;默认情况会给客户机提供 qemu64 或 qemu32 的基本 CPU 模型。这样做可以对 CPU 特性提供一些高级的过滤功能，让客户机在同一组硬件平台上的动态迁移会更加平滑和安全。
在客户机中查看 CPU 信息 (cat /proc/cpuinfo)，model name 就是当前 CPU 模型的名称。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;调用实例&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-riscv32 -cpu rv32
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;accel-namepropvalue&#34;&gt;&lt;code&gt;accel name[,prop=value[,...]]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
This is used to enable an accelerator. Depending on the target architecture, kvm, xen, hax, hvf, nvmm, whpx or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize.&lt;/li&gt;
&lt;li&gt;子参数
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;igd-passthru=on|off&lt;/code&gt;
When Xen is in use, this option controls whether Intel integrated graphics devices can be passed through to the guest (default=off)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kernel-irqchip=on|off|split&lt;/code&gt;
Controls KVM in-kernel irqchip support. The default is full acceleration of the interrupt controllers. On x86, split irqchip reduces the kernel attack surface, at a performance cost for non-MSI interrupts. Disabling the in-kernel irqchip completely is not recommended except for debugging purposes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kvm-shadow-mem=size&lt;/code&gt;
Defines the size of the KVM shadow MMU.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;split-wx=on|off&lt;/code&gt;
Controls the use of split w^x mapping for the TCG code generation buffer. Some operating systems require this to be enabled, and in such a case this will default on. On other operating systems, this will default off, but one may enable this for testing or debugging.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tb-size=n&lt;/code&gt;
Controls the size (in MiB) of the TCG translation block cache.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;thread=single|multi&lt;/code&gt;
Controls number of TCG threads. When the TCG is multi-threaded there will be one thread per vCPU therefore taking advantage of additional host cores. The default is to enable multi-threading where both the back-end and front-ends support it and no incompatible TCG features have been enabled (e.g. icount/replay).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dirty-ring-size=n&lt;/code&gt;
When the KVM accelerator is used, it controls the size of the per-vCPU dirty page ring buffer (number of entries for each vCPU). It should be a value that is power of two, and it should be 1024 or bigger (but still less than the maximum value that the kernel supports). 4096 could be a good initial value if you have no idea which is the best. Set this value to 0 to disable the feature. By default, this feature is disabled (dirty-ring-size=0). When enabled, KVM will instead record dirty pages in a bitmap.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;smp-cpusnmaxcpusmaxcpussocketssocketsdiesdiescorescoresthreadsthreads&#34;&gt;&lt;code&gt;smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能
配置客户机的 SMP（Symmetric Multi-Processing），对称多处理机&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子参数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[cpus=]n&lt;/code&gt;
设置客户机中使用逻辑的 CPU 数量（默认值是 1）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,maxcpus=cpus]&lt;/code&gt;
设置客户机最大可能被使用的 CPU 数量（可以用热插拔 hot-plug 添加 CPU，不能超过 maxcpus 上限）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,cores=cores]&lt;/code&gt;
设置每个 CPU socket 上的 core 数量（默认值是 1）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,threads=threads]&lt;/code&gt;
设置每个 CPU core 上的线程数（默认值是 1）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,sockets=sockets]&lt;/code&gt;
设置客户机中总的 CPU socket 数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用实例&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-x86_64  -smp 1,sockets=1,cores=2,threads=2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;-numa-nodememsizecpusfirstcpu-lastcpunodeidnodeinitiatorinitiator&#34;&gt;&lt;code&gt;-numa node[,mem=size][,cpus=firstcpu[-lastcpu]][,nodeid=node][,initiator=initiator]&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id=&#34;-numa-nodememdevidcpusfirstcpu-lastcpunodeidnodeinitiatorinitiator&#34;&gt;&lt;code&gt;-numa node[,memdev=id][,cpus=firstcpu[-lastcpu]][,nodeid=node][,initiator=initiator]&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id=&#34;-numa-distsrcsourcedstdestinationvaldistance&#34;&gt;&lt;code&gt;-numa dist,src=source,dst=destination,val=distance&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id=&#34;-numa-cpunode-idnodesocket-idxcore-idythread-idz&#34;&gt;&lt;code&gt;-numa cpu,node-id=node[,socket-id=x][,core-id=y][,thread-id=z]&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id=&#34;-numa-hmat-lbinitiatornodetargetnodehierarchyhierarchydata-typetpyelatencylatbandwidthbw&#34;&gt;&lt;code&gt;-numa hmat-lb,initiator=node,target=node,hierarchy=hierarchy,data-type=tpye[,latency=lat][,bandwidth=bw]&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id=&#34;-numa-hmat-cachenode-idnodesizesizelevellevelassociativitystrpolicystrlinesize&#34;&gt;&lt;code&gt;-numa hmat-cache,node-id=node,size=size,level=level[,associativity=str][,policy=str][,line=size]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-add-fd-fdfdsetsetopaqueopaque&#34;&gt;&lt;code&gt;-add-fd fd=fd,set=set[,opaque=opaque]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-set-groupidargvalue&#34;&gt;&lt;code&gt;-set group.id.arg=value&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-global-driverpropvalue&#34;&gt;&lt;code&gt;-global driver.prop=value&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-global-driverdriverpropertypropertyvaluevalue&#34;&gt;&lt;code&gt;-global driver=driver,property=property,value=value&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-boot-orderdrivesoncedrivesmenuonoffsplashsp_namesplash-timesp_timereboot-timeoutrb_timeoutstrictonoff&#34;&gt;&lt;code&gt;-boot [order=drives][,once=drives][,menu=on|off][,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_timeout][,strict=on|off]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
设置客户机启动顺序&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;在 qemu 模拟的 x86 平台中，用&amp;quot;a&amp;quot;、&amp;ldquo;b&amp;quot;分别表示第一和第二软驱，用&amp;quot;c&amp;quot;表示第一个硬盘，用&amp;quot;d&amp;quot;表示 CD-ROM 光驱，用&amp;quot;n&amp;quot;表示从网络启动。
默认从硬盘启动。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;子参数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[order=drives]&lt;/code&gt;
设置启动顺序。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,once=drives]&lt;/code&gt;
只设置下一次启动的顺序，再重启后无效。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,menu=on|off]&lt;/code&gt;
只要固件/BIOS 支持，就可以启用交互式引导菜单/提示。默认为非交互式引导。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,splash=sp_name]&lt;/code&gt;
如果固件/BIOS 支持选项 splash=sp_name 和 menu=on，则可以将启动画面传递给 bios，使用户能够将其显示为徽标。目前 Seabios for X86 系统支持它。限制：启动文件可以是 24 BPP 格式（真彩色）的 jpeg 文件或 BMP 文件。分辨率应该是 SVGA 模式支持的，推荐 320x240、640x480、800x640。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,splash-time=sp_time]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,reboot-timeout=rb_timeout]&lt;/code&gt;
引导失败时，客户机将暂停 &lt;code&gt;rb_timeout&lt;/code&gt; 毫秒，然后重新启动。如果 &lt;code&gt;rb_timeout&lt;/code&gt; 为 &amp;lsquo;-1&amp;rsquo;，客户机不会重启，qemu 默认将 &amp;lsquo;-1&amp;rsquo; 传递给 bios。目前 Seabios for X86 系统支持它。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,strict=on|off]&lt;/code&gt;
只要固件/BIOS 支持，就通过严格启动。这仅在 bootindex 选项更改引导优先级时有效。默认为非严格引导。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用实例&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 尝试先从网络启动，然后从硬盘启动
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-x86_64 -boot order=nc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 先从光驱启动，重启后切换回默认顺序
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-x86_64 -boot once=d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 5 秒钟的启动画面。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-x86_64 -boot menu=on,splash=/root/boot.bmp,splash-time=5000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-m-sizemegsslotsnmaxmemsize&#34;&gt;&lt;code&gt;-m [size=]megs[,slots=n,maxmem=size]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能
将客户机内存设置为 &lt;code&gt;megs&lt;/code&gt; M字节。默认值为 &lt;code&gt;128 MiB&lt;/code&gt;。或者，也可以使用“M”或“G”的后缀。齐。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子参数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[size=]megs&lt;/code&gt;
将客户机内存设置为 &lt;code&gt;megs&lt;/code&gt; M字节&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,slots=n,maxmem=size]&lt;/code&gt;
可用于设置可热插拔内存插槽的数量和最大内存数量。&lt;code&gt;maxmem&lt;/code&gt; 必须与页面大小对&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用实例
以下命令行将客户机启动 RAM 大小设置为 1GB，创建 3 个插槽以热插拔额外内存，并将客户机可以达到的最大内存设置为 4GB：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-x86_64 -m 1G,slots=3,maxmem=4G
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果未指定 &lt;code&gt;slot&lt;/code&gt; 和 &lt;code&gt;maxmem&lt;/code&gt;，则不会启用内存热插拔，并且客户机内存永远不会增加。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-mem-path-path&#34;&gt;&lt;code&gt;-mem-path path&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
使用huge page。对于内存访问密集型的应用，使用&lt;code&gt;huge page&lt;/code&gt;是可以比较明显地提高客户机性能。 使用&lt;code&gt;huge page&lt;/code&gt;的内存不能被换出（swap out），也不能使用&lt;code&gt;ballooning&lt;/code&gt;方式自动增长。&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-mem-prealloc&#34;&gt;&lt;code&gt;-mem-prealloc&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
使宿主机在客户机启动时就全部分配好客户机的内存&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-k-language&#34;&gt;&lt;code&gt;-k language&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能
设置键盘布局语言，默认为&lt;code&gt;en-us&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子参数
可用布局：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ar  de-ch  es  fo     fr-ca  hu  ja  mk     no  pt-br  sv
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;da  en-gb  et  fr     fr-ch  is  lt  nl     pl  ru     th
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;de  en-us  fi  fr-be  hr     it  lv  nl-be  pt  sl     tr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用实例&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;块设备参数-block-device-options&#34;&gt;块设备参数 Block device options&lt;/h2&gt;
&lt;h3 id=&#34;fda-file&#34;&gt;&lt;code&gt;fda file&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
为客户机指定软盘设备，指定客户机的第一个软盘设备，在客户机中显示为&lt;code&gt;/dev/fd0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;fdb-file&#34;&gt;&lt;code&gt;fdb file&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
为客户机指定软盘设备，指定客户机的第一个软盘设备，在客户机中显示为&lt;code&gt;/dev/fd1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;hda-file&#34;&gt;&lt;code&gt;hda file&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id=&#34;hdb-file&#34;&gt;&lt;code&gt;hdb file&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id=&#34;hdc-file&#34;&gt;&lt;code&gt;hdc file&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id=&#34;hdd-file&#34;&gt;&lt;code&gt;hdd file&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
为客户机指定块存储设备，指定客户机种的第一个 IDE 设备&lt;/li&gt;
&lt;li&gt;子参数
若客户机使用&lt;code&gt;PIIX_IDE&lt;/code&gt;驱动，显示为&lt;code&gt;/dev/hda&lt;/code&gt;设备；
若客户机使用&lt;code&gt;ata_piix&lt;/code&gt;驱动，显示为&lt;code&gt;/dev/sda&lt;/code&gt;设备。
若没有使用&lt;code&gt;-hdx&lt;/code&gt;的参数，则默认使用&lt;code&gt;-hda&lt;/code&gt;参数；
可以将宿主机的一块硬盘作为&lt;code&gt;-hda&lt;/code&gt;的参数使用；
若文件名包含逗号，应使用两个连续的逗号进行转义。&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-cdrom-file&#34;&gt;&lt;code&gt;-cdrom file&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
为客户机指定光盘 CD-ROM。可以将宿主机的光驱&lt;code&gt;/dev/cdrom&lt;/code&gt;设备作为&lt;code&gt;-cdrom&lt;/code&gt;参数使用。&lt;code&gt;-cdrom&lt;/code&gt;参数不能与&lt;code&gt;-hdc&lt;/code&gt;参数同时使用，因为&lt;code&gt;-cdrom&lt;/code&gt;就是客户机里的第三个 IDE 设备&lt;/li&gt;
&lt;li&gt;子参数&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-blockdev-optionoptionoption&#34;&gt;&lt;code&gt;-blockdev option[,option[,option[,...]]]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子参数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用实例&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;-drive-optionoptionoption&#34;&gt;&lt;code&gt;-drive option[,option[,option[,...]]]&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;功能
定义一个存储驱动器&lt;/li&gt;
&lt;li&gt;子参数
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[file=file]&lt;/code&gt;
加载&lt;code&gt;file&lt;/code&gt;镜像文件到客户机的驱动器中。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,if=type]&lt;/code&gt;
指定驱动器使用的接口类型：可用的类类型有：&lt;code&gt;ide&lt;/code&gt;、&lt;code&gt;scsi&lt;/code&gt;、&lt;code&gt;virtio&lt;/code&gt;、&lt;code&gt;sd&lt;/code&gt;、&lt;code&gt;floopy&lt;/code&gt;、&lt;code&gt;pflash&lt;/code&gt;等。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,bus=n]&lt;/code&gt;
设置驱动器在客户机中的总线编号。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,unit=m]&lt;/code&gt;
设置驱动器在客户机中的单元编号。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,media=d]&lt;/code&gt;
设置驱动器中媒介的类型，值为 disk 或 cdrom。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,index=i]&lt;/code&gt;
设置在通一种接口的驱动器中的索引编号。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,snapshot=on|off]&lt;/code&gt;
当值为 on 时，qemu 不会将磁盘数据的更改写回到镜像文件中，而是写到临时文件中，可以在 qemu moinitor 中使用 commit 命令强制将磁盘数据保存回镜像文件中。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,cache=writethrough|writeback|none|directsync|unsafe]&lt;/code&gt;
设置宿主机对块设备数据访问的 cache 模式。，
&lt;code&gt;writethrough&lt;/code&gt;（直写模式）：调用 write 写入数据的同时将数据写入磁盘缓存和后端块设备中。
&lt;code&gt;writeback&lt;/code&gt;（回写模式）：调用 write 写入数据时只将数据写入到磁盘缓存中，当数据被换出缓存时才写入到后端存储中。优点写入数据块，缺点系统掉电数据无法恢复。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,aio=threads|native]&lt;/code&gt;
选择异步 IO 的方式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;threads&lt;/code&gt;
为 aio 参数的默认值，让一个线程池去处理异步 IO；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;native&lt;/code&gt;
只适用于 cache=none 的情况，使用的是 Linux 原生的 AIO。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,format=f]&lt;/code&gt;
指定使用的磁盘格式，默认是 QEMU 自动检测磁盘格式的。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,serial=s]&lt;/code&gt;
指定分配给设备的序列号。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,addr=A]&lt;/code&gt;
分配给驱动器控制器的 PCI 地址，只在使用 virtio 接口时适用。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[,id=name]&lt;/code&gt;
设置驱动器的 ID，可以在 QEMU monitor 中用 info block 看到。
&lt;code&gt;[,readonly=on|off]&lt;/code&gt;
设置驱动器是否只读。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;调用实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;usb-参数-usb-convenience-options&#34;&gt;USB 参数 USB convenience options&lt;/h2&gt;
&lt;h2 id=&#34;显示参数-display-options&#34;&gt;显示参数 Display options&lt;/h2&gt;
&lt;h2 id=&#34;仅限-i386-架构的参数-i386-target-only&#34;&gt;仅限 i386 架构的参数 i386 target only&lt;/h2&gt;
&lt;h2 id=&#34;网络参数-network-options&#34;&gt;网络参数 Network options&lt;/h2&gt;
&lt;h2 id=&#34;字符设备参数-character-device-options&#34;&gt;字符设备参数 Character device options&lt;/h2&gt;
&lt;h2 id=&#34;tpm-设备-tpm-device-options&#34;&gt;TPM 设备 TPM device options&lt;/h2&gt;
&lt;h2 id=&#34;指定启动指引-linuxmultiboot-boot-specific&#34;&gt;指定启动指引 Linux/Multiboot boot specific&lt;/h2&gt;
&lt;p&gt;当使用该调用参数时，你可以使用给定的 Linux 或者多重引导内核，而不需要安装内核到一个光盘中。这样可以更方便地测试不同内核。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-kernel bzImage&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能
用 bzImage 作为内核镜像，也可以使用其他启动格式。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-append cmdline&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能
用&lt;code&gt;cmd&lt;/code&gt;命令行，作为内核的命令行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-initrd file&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能
用文件作为初始化 ram&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-initrd &amp;quot;file1 arg=foo,file2&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能
此语法仅适用于多重引导
使用 &lt;code&gt;file1&lt;/code&gt; 和 &lt;code&gt;file2&lt;/code&gt; 作为模块并将 &lt;code&gt;arg=foo&lt;/code&gt; 作为参数传递给第一个模块&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-dtb file&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能
将文件用作设备树二进制 (dtb) 映像并在启动时将其传递给内核&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<h1 id="调用文档">调用文档</h1>
<p><code>qemu-system-x86_64 [options] [disk_image] </code>
<code>disk_image</code>是 IDE 硬盘 0 的原始硬盘映像。某些目标不需要磁盘映像。</p>
<h2 id="标准参数-standard-options">标准参数 Standard options</h2>
<h3 id="-h"><code>-h</code></h3>
<ul>
<li>
<p>功能
显示帮助信息并退出</p>
</li>
<li>
<p>子参数</p>
</li>
<li>
<p>调用实例</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-system-riscv32 -h
</span></span></code></pre></div></li>
</ul>
<h3 id="-version"><code>-version</code></h3>
<ul>
<li>
<p>功能
显示 qemu 版本信息并退出</p>
</li>
<li>
<p>子参数</p>
</li>
<li>
<p>调用实例</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-system-riscv32 -version
</span></span></code></pre></div></li>
</ul>
<h3 id="-machine-typenamepropvalue"><code>-machine [type=]name[,prop=value[,...]]</code></h3>
<ul>
<li>
<p>功能
通过名称选择模拟器。使用 <code>-machine help</code> 可以查看可用的模拟器。
对于支持跨版本实时迁移兼容性的架构，每个版本都会引入一个新的版本化模拟器类型。例如，2.8.0 版本为 <code>x86_64/i686</code> 架构引入了<code>“pc-i440fx-2.8”</code>和<code>“pc-q35-2.8”</code>。</p>
</li>
<li>
<p>子参数
为了允许用户从 QEMU 2.8.0 版实时迁移到 QEMU 2.9.0 版，2.9.0 版也必须支持<code>“pc-i440fx-2.8”</code>和<code>“pc-q35-2.8”</code>机器。为了允许用户在升级时实时迁移 VMs 跳过多个中间版本，QEMU 的新版本将支持多个以前版本的机器类型。
支持的机器属性有：</p>
<ul>
<li><code>accel=accels1[:accels2[:...]]</code>
This is used to enable an accelerator. Depending on the target architecture, kvm, xen, hax, hvf, nvmm, whpx or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize.</li>
<li><code>vmport=on|off|auto</code>
Enables emulation of VMWare IO port, for vmmouse etc. auto says to select the value based on accel. For accel=xen the default is off otherwise the default is on.</li>
<li><code>dump-guest-core=on|off</code>
Include guest memory in a core dump. The default is on.</li>
<li><code>mem-merge=on|off</code>
Enables or disables memory merge support. This feature, when supported by the host, de-duplicates identical memory pages among VMs instances (enabled by default).</li>
<li><code>aes-key-wrap=on|off</code>
Enables or disables AES key wrapping support on s390-ccw hosts. This feature controls whether AES wrapping keys will be created to allow execution of AES cryptographic functions. The default is on.</li>
<li><code>dea-key-wrap=on|off</code>
Enables or disables DEA key wrapping support on s390-ccw hosts. This feature controls whether DEA wrapping keys will be created to allow execution of DEA cryptographic functions. The default is on.</li>
<li><code>nvdimm=on|off</code>
Enables or disables NVDIMM support. The default is off.</li>
<li><code>memory-encryption=</code>
Memory encryption object to use. The default is none.</li>
<li><code>hmat=on|off</code>
Enables or disables ACPI Heterogeneous Memory Attribute Table (HMAT) support. The default is off.</li>
<li><code>memory-backend='id'</code>
An alternative to legacy -mem-path and mem-prealloc options. Allows to use a memory backend as main RAM.
For example: <code>:: -object memory-backend-file,id=pc.ram,size=512M,mem-path=/hugetlbfs,prealloc=on,share=on -machine memory-backend=pc.ram -m 512M</code>
Migration compatibility note: a) as backend id one shall use value of ‘default-ram-id’, advertised by machine type (available via query-machines QMP command), if migration to/from old QEMU (&lt;5.0) is expected. b) for machine types 4.0 and older, user shall use x-use-canonical-path-for-ramblock-id=off backend option if migration to/from old QEMU (&lt;5.0) is expected. For example: :: -object memory-backend-ram,id=pc.ram,size=512M,x-use-canonical-path-for-ramblock-id=off -machine memory-backend=pc.ram -m 512M</li>
</ul>
</li>
<li>
<p>调用实例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-system-riscv32 -machine virt,mem-merge=on
</span></span></code></pre></div></li>
</ul>
<h3 id="-cpu-model"><code>-cpu model</code></h3>
<ul>
<li>功能
选择 CPU 型号（<code>-cpu help</code>显示帮助列表和附加功能的选项）</li>
</ul>
<blockquote>
<p>默认情况会给客户机提供 qemu64 或 qemu32 的基本 CPU 模型。这样做可以对 CPU 特性提供一些高级的过滤功能，让客户机在同一组硬件平台上的动态迁移会更加平滑和安全。
在客户机中查看 CPU 信息 (cat /proc/cpuinfo)，model name 就是当前 CPU 模型的名称。</p>
</blockquote>
<ul>
<li>
<p>调用实例</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-system-riscv32 -cpu rv32
</span></span></code></pre></div></li>
</ul>
<h3 id="accel-namepropvalue"><code>accel name[,prop=value[,...]]</code></h3>
<ul>
<li>功能
This is used to enable an accelerator. Depending on the target architecture, kvm, xen, hax, hvf, nvmm, whpx or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize.</li>
<li>子参数
<ul>
<li><code>igd-passthru=on|off</code>
When Xen is in use, this option controls whether Intel integrated graphics devices can be passed through to the guest (default=off)</li>
<li><code>kernel-irqchip=on|off|split</code>
Controls KVM in-kernel irqchip support. The default is full acceleration of the interrupt controllers. On x86, split irqchip reduces the kernel attack surface, at a performance cost for non-MSI interrupts. Disabling the in-kernel irqchip completely is not recommended except for debugging purposes.</li>
<li><code>kvm-shadow-mem=size</code>
Defines the size of the KVM shadow MMU.</li>
<li><code>split-wx=on|off</code>
Controls the use of split w^x mapping for the TCG code generation buffer. Some operating systems require this to be enabled, and in such a case this will default on. On other operating systems, this will default off, but one may enable this for testing or debugging.</li>
<li><code>tb-size=n</code>
Controls the size (in MiB) of the TCG translation block cache.</li>
<li><code>thread=single|multi</code>
Controls number of TCG threads. When the TCG is multi-threaded there will be one thread per vCPU therefore taking advantage of additional host cores. The default is to enable multi-threading where both the back-end and front-ends support it and no incompatible TCG features have been enabled (e.g. icount/replay).</li>
<li><code>dirty-ring-size=n</code>
When the KVM accelerator is used, it controls the size of the per-vCPU dirty page ring buffer (number of entries for each vCPU). It should be a value that is power of two, and it should be 1024 or bigger (but still less than the maximum value that the kernel supports). 4096 could be a good initial value if you have no idea which is the best. Set this value to 0 to disable the feature. By default, this feature is disabled (dirty-ring-size=0). When enabled, KVM will instead record dirty pages in a bitmap.</li>
</ul>
</li>
</ul>
<h3 id="smp-cpusnmaxcpusmaxcpussocketssocketsdiesdiescorescoresthreadsthreads"><code>smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]</code></h3>
<ul>
<li>
<p>功能
配置客户机的 SMP（Symmetric Multi-Processing），对称多处理机</p>
</li>
<li>
<p>子参数</p>
<ul>
<li><code>[cpus=]n</code>
设置客户机中使用逻辑的 CPU 数量（默认值是 1）。</li>
<li><code>[,maxcpus=cpus]</code>
设置客户机最大可能被使用的 CPU 数量（可以用热插拔 hot-plug 添加 CPU，不能超过 maxcpus 上限）。</li>
<li><code>[,cores=cores]</code>
设置每个 CPU socket 上的 core 数量（默认值是 1）。</li>
<li><code>[,threads=threads]</code>
设置每个 CPU core 上的线程数（默认值是 1）。</li>
<li><code>[,sockets=sockets]</code>
设置客户机中总的 CPU socket 数量。</li>
</ul>
</li>
<li>
<p>调用实例</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-system-x86_64  -smp 1,sockets=1,cores=2,threads=2
</span></span></code></pre></div><h3 id="-numa-nodememsizecpusfirstcpu-lastcpunodeidnodeinitiatorinitiator"><code>-numa node[,mem=size][,cpus=firstcpu[-lastcpu]][,nodeid=node][,initiator=initiator]</code></h3>
<h3 id="-numa-nodememdevidcpusfirstcpu-lastcpunodeidnodeinitiatorinitiator"><code>-numa node[,memdev=id][,cpus=firstcpu[-lastcpu]][,nodeid=node][,initiator=initiator]</code></h3>
<h3 id="-numa-distsrcsourcedstdestinationvaldistance"><code>-numa dist,src=source,dst=destination,val=distance</code></h3>
<h3 id="-numa-cpunode-idnodesocket-idxcore-idythread-idz"><code>-numa cpu,node-id=node[,socket-id=x][,core-id=y][,thread-id=z]</code></h3>
<h3 id="-numa-hmat-lbinitiatornodetargetnodehierarchyhierarchydata-typetpyelatencylatbandwidthbw"><code>-numa hmat-lb,initiator=node,target=node,hierarchy=hierarchy,data-type=tpye[,latency=lat][,bandwidth=bw]</code></h3>
<h3 id="-numa-hmat-cachenode-idnodesizesizelevellevelassociativitystrpolicystrlinesize"><code>-numa hmat-cache,node-id=node,size=size,level=level[,associativity=str][,policy=str][,line=size]</code></h3>
<ul>
<li>功能</li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="-add-fd-fdfdsetsetopaqueopaque"><code>-add-fd fd=fd,set=set[,opaque=opaque]</code></h3>
<ul>
<li>功能</li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="-set-groupidargvalue"><code>-set group.id.arg=value</code></h3>
<ul>
<li>功能</li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="-global-driverpropvalue"><code>-global driver.prop=value</code></h3>
<ul>
<li>功能</li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="-global-driverdriverpropertypropertyvaluevalue"><code>-global driver=driver,property=property,value=value</code></h3>
<ul>
<li>功能</li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="-boot-orderdrivesoncedrivesmenuonoffsplashsp_namesplash-timesp_timereboot-timeoutrb_timeoutstrictonoff"><code>-boot [order=drives][,once=drives][,menu=on|off][,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_timeout][,strict=on|off]</code></h3>
<ul>
<li>功能
设置客户机启动顺序</li>
</ul>
<blockquote>
<p>在 qemu 模拟的 x86 平台中，用&quot;a&quot;、&ldquo;b&quot;分别表示第一和第二软驱，用&quot;c&quot;表示第一个硬盘，用&quot;d&quot;表示 CD-ROM 光驱，用&quot;n&quot;表示从网络启动。
默认从硬盘启动。</p>
</blockquote>
<ul>
<li>
<p>子参数</p>
<ul>
<li><code>[order=drives]</code>
设置启动顺序。</li>
<li><code>[,once=drives]</code>
只设置下一次启动的顺序，再重启后无效。</li>
<li><code>[,menu=on|off]</code>
只要固件/BIOS 支持，就可以启用交互式引导菜单/提示。默认为非交互式引导。</li>
<li><code>[,splash=sp_name]</code>
如果固件/BIOS 支持选项 splash=sp_name 和 menu=on，则可以将启动画面传递给 bios，使用户能够将其显示为徽标。目前 Seabios for X86 系统支持它。限制：启动文件可以是 24 BPP 格式（真彩色）的 jpeg 文件或 BMP 文件。分辨率应该是 SVGA 模式支持的，推荐 320x240、640x480、800x640。</li>
<li><code>[,splash-time=sp_time]</code></li>
<li><code>[,reboot-timeout=rb_timeout]</code>
引导失败时，客户机将暂停 <code>rb_timeout</code> 毫秒，然后重新启动。如果 <code>rb_timeout</code> 为 &lsquo;-1&rsquo;，客户机不会重启，qemu 默认将 &lsquo;-1&rsquo; 传递给 bios。目前 Seabios for X86 系统支持它。</li>
<li><code>[,strict=on|off]</code>
只要固件/BIOS 支持，就通过严格启动。这仅在 bootindex 选项更改引导优先级时有效。默认为非严格引导。</li>
</ul>
</li>
<li>
<p>调用实例</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 尝试先从网络启动，然后从硬盘启动
</span></span><span class="line"><span class="cl">qemu-system-x86_64 -boot order=nc
</span></span><span class="line"><span class="cl"># 先从光驱启动，重启后切换回默认顺序
</span></span><span class="line"><span class="cl">qemu-system-x86_64 -boot once=d
</span></span><span class="line"><span class="cl"># 5 秒钟的启动画面。
</span></span><span class="line"><span class="cl">qemu-system-x86_64 -boot menu=on,splash=/root/boot.bmp,splash-time=5000
</span></span></code></pre></div></li>
</ul>
<h3 id="-m-sizemegsslotsnmaxmemsize"><code>-m [size=]megs[,slots=n,maxmem=size]</code></h3>
<ul>
<li>
<p>功能
将客户机内存设置为 <code>megs</code> M字节。默认值为 <code>128 MiB</code>。或者，也可以使用“M”或“G”的后缀。齐。</p>
</li>
<li>
<p>子参数</p>
<ul>
<li><code>[size=]megs</code>
将客户机内存设置为 <code>megs</code> M字节</li>
<li><code>[,slots=n,maxmem=size]</code>
可用于设置可热插拔内存插槽的数量和最大内存数量。<code>maxmem</code> 必须与页面大小对</li>
</ul>
</li>
<li>
<p>调用实例
以下命令行将客户机启动 RAM 大小设置为 1GB，创建 3 个插槽以热插拔额外内存，并将客户机可以达到的最大内存设置为 4GB：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-system-x86_64 -m 1G,slots=3,maxmem=4G
</span></span></code></pre></div><p>如果未指定 <code>slot</code> 和 <code>maxmem</code>，则不会启用内存热插拔，并且客户机内存永远不会增加。</p>
</li>
</ul>
<h3 id="-mem-path-path"><code>-mem-path path</code></h3>
<ul>
<li>功能
使用huge page。对于内存访问密集型的应用，使用<code>huge page</code>是可以比较明显地提高客户机性能。 使用<code>huge page</code>的内存不能被换出（swap out），也不能使用<code>ballooning</code>方式自动增长。</li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="-mem-prealloc"><code>-mem-prealloc</code></h3>
<ul>
<li>功能
使宿主机在客户机启动时就全部分配好客户机的内存</li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="-k-language"><code>-k language</code></h3>
<ul>
<li>
<p>功能
设置键盘布局语言，默认为<code>en-us</code></p>
</li>
<li>
<p>子参数
可用布局：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ar  de-ch  es  fo     fr-ca  hu  ja  mk     no  pt-br  sv
</span></span><span class="line"><span class="cl">da  en-gb  et  fr     fr-ch  is  lt  nl     pl  ru     th
</span></span><span class="line"><span class="cl">de  en-us  fi  fr-be  hr     it  lv  nl-be  pt  sl     tr
</span></span></code></pre></div></li>
<li>
<p>调用实例</p>
</li>
</ul>
<h2 id="块设备参数-block-device-options">块设备参数 Block device options</h2>
<h3 id="fda-file"><code>fda file</code></h3>
<ul>
<li>功能
为客户机指定软盘设备，指定客户机的第一个软盘设备，在客户机中显示为<code>/dev/fd0</code></li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="fdb-file"><code>fdb file</code></h3>
<ul>
<li>功能
为客户机指定软盘设备，指定客户机的第一个软盘设备，在客户机中显示为<code>/dev/fd1</code></li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="hda-file"><code>hda file</code></h3>
<h3 id="hdb-file"><code>hdb file</code></h3>
<h3 id="hdc-file"><code>hdc file</code></h3>
<h3 id="hdd-file"><code>hdd file</code></h3>
<ul>
<li>功能
为客户机指定块存储设备，指定客户机种的第一个 IDE 设备</li>
<li>子参数
若客户机使用<code>PIIX_IDE</code>驱动，显示为<code>/dev/hda</code>设备；
若客户机使用<code>ata_piix</code>驱动，显示为<code>/dev/sda</code>设备。
若没有使用<code>-hdx</code>的参数，则默认使用<code>-hda</code>参数；
可以将宿主机的一块硬盘作为<code>-hda</code>的参数使用；
若文件名包含逗号，应使用两个连续的逗号进行转义。</li>
<li>调用实例</li>
</ul>
<h3 id="-cdrom-file"><code>-cdrom file</code></h3>
<ul>
<li>功能
为客户机指定光盘 CD-ROM。可以将宿主机的光驱<code>/dev/cdrom</code>设备作为<code>-cdrom</code>参数使用。<code>-cdrom</code>参数不能与<code>-hdc</code>参数同时使用，因为<code>-cdrom</code>就是客户机里的第三个 IDE 设备</li>
<li>子参数</li>
<li>调用实例</li>
</ul>
<h3 id="-blockdev-optionoptionoption"><code>-blockdev option[,option[,option[,...]]]</code></h3>
<ul>
<li>
<p>功能</p>
</li>
<li>
<p>子参数</p>
</li>
<li>
<p>调用实例</p>
</li>
</ul>
<h3 id="-drive-optionoptionoption"><code>-drive option[,option[,option[,...]]]</code></h3>
<ul>
<li>功能
定义一个存储驱动器</li>
<li>子参数
<ul>
<li><code>[file=file]</code>
加载<code>file</code>镜像文件到客户机的驱动器中。</li>
<li><code>[,if=type]</code>
指定驱动器使用的接口类型：可用的类类型有：<code>ide</code>、<code>scsi</code>、<code>virtio</code>、<code>sd</code>、<code>floopy</code>、<code>pflash</code>等。</li>
<li><code>[,bus=n]</code>
设置驱动器在客户机中的总线编号。</li>
<li><code>[,unit=m]</code>
设置驱动器在客户机中的单元编号。</li>
<li><code>[,media=d]</code>
设置驱动器中媒介的类型，值为 disk 或 cdrom。</li>
<li><code>[,index=i]</code>
设置在通一种接口的驱动器中的索引编号。</li>
<li><code>[,snapshot=on|off]</code>
当值为 on 时，qemu 不会将磁盘数据的更改写回到镜像文件中，而是写到临时文件中，可以在 qemu moinitor 中使用 commit 命令强制将磁盘数据保存回镜像文件中。</li>
<li><code>[,cache=writethrough|writeback|none|directsync|unsafe]</code>
设置宿主机对块设备数据访问的 cache 模式。，
<code>writethrough</code>（直写模式）：调用 write 写入数据的同时将数据写入磁盘缓存和后端块设备中。
<code>writeback</code>（回写模式）：调用 write 写入数据时只将数据写入到磁盘缓存中，当数据被换出缓存时才写入到后端存储中。优点写入数据块，缺点系统掉电数据无法恢复。</li>
<li><code>[,aio=threads|native]</code>
选择异步 IO 的方式</li>
<li><code>threads</code>
为 aio 参数的默认值，让一个线程池去处理异步 IO；</li>
<li><code>native</code>
只适用于 cache=none 的情况，使用的是 Linux 原生的 AIO。</li>
<li><code>[,format=f]</code>
指定使用的磁盘格式，默认是 QEMU 自动检测磁盘格式的。</li>
<li><code>[,serial=s]</code>
指定分配给设备的序列号。</li>
<li><code>[,addr=A]</code>
分配给驱动器控制器的 PCI 地址，只在使用 virtio 接口时适用。</li>
<li><code>[,id=name]</code>
设置驱动器的 ID，可以在 QEMU monitor 中用 info block 看到。
<code>[,readonly=on|off]</code>
设置驱动器是否只读。</li>
</ul>
</li>
<li>调用实例</li>
</ul>
<h2 id="usb-参数-usb-convenience-options">USB 参数 USB convenience options</h2>
<h2 id="显示参数-display-options">显示参数 Display options</h2>
<h2 id="仅限-i386-架构的参数-i386-target-only">仅限 i386 架构的参数 i386 target only</h2>
<h2 id="网络参数-network-options">网络参数 Network options</h2>
<h2 id="字符设备参数-character-device-options">字符设备参数 Character device options</h2>
<h2 id="tpm-设备-tpm-device-options">TPM 设备 TPM device options</h2>
<h2 id="指定启动指引-linuxmultiboot-boot-specific">指定启动指引 Linux/Multiboot boot specific</h2>
<p>当使用该调用参数时，你可以使用给定的 Linux 或者多重引导内核，而不需要安装内核到一个光盘中。这样可以更方便地测试不同内核。</p>
<ul>
<li>
<p><code>-kernel bzImage</code></p>
<ul>
<li>功能
用 bzImage 作为内核镜像，也可以使用其他启动格式。</li>
</ul>
</li>
<li>
<p><code>-append cmdline</code></p>
<ul>
<li>功能
用<code>cmd</code>命令行，作为内核的命令行</li>
</ul>
</li>
<li>
<p><code>-initrd file</code></p>
<ul>
<li>功能
用文件作为初始化 ram</li>
</ul>
</li>
<li>
<p><code>-initrd &quot;file1 arg=foo,file2&quot;</code></p>
<ul>
<li>功能
此语法仅适用于多重引导
使用 <code>file1</code> 和 <code>file2</code> 作为模块并将 <code>arg=foo</code> 作为参数传递给第一个模块</li>
</ul>
</li>
<li>
<p><code>-dtb file</code></p>
<ul>
<li>功能
将文件用作设备树二进制 (dtb) 映像并在启动时将其传递给内核</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>QEMU 初识</title>
      <link>https://lifeislife.cn/posts/qemu%E5%88%9D%E8%AF%86/</link>
      <pubDate>Fri, 23 Jul 2021 11:54:49 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E5%88%9D%E8%AF%86/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;
&lt;p&gt;QEMU 是一款开源的模拟器及虚拟机监管器 (Virtual Machine Monitor, VMM)。QEMU 主要提供两种功能给用户使用。一是作为用户态模拟器，利用动态代码翻译机制来执行不同于主机架构的代码。二是作为虚拟机监管器，模拟全系统，利用其他 VMM(Xen, KVM, etc) 来使用硬件提供的虚拟化支持，创建接近于主机性能的虚拟机。&lt;/p&gt;
&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;
&lt;h3 id=&#34;使用包管理安装&#34;&gt;使用包管理安装&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install qemu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;使用源码安装&#34;&gt;使用源码安装&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;wget&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;wget&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;download&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;org&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;6.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rc3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;tar&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;xvJf&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;6.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rc3&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tar&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;xz&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;qemu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;6.1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rc3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;安装相关库&#34;&gt;安装相关库&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install libglib2.0-dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt-get install ninja-build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt install g++
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt install libpixman-1-dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt install libsdl2-dev -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;配置&#34;&gt;配置&lt;/h3&gt;
&lt;p&gt;通过&lt;code&gt;./configure --help&lt;/code&gt; 的查看编译时的选项，&lt;code&gt;--target-list&lt;/code&gt;选项为可选的模拟器，默认全选。
&lt;code&gt;--target-list&lt;/code&gt; 中的 &lt;code&gt;xxx-soft&lt;/code&gt; 和 &lt;code&gt;xxx-linux-user&lt;/code&gt; 分别指系统模拟器和应用程序模拟器，生成的二进制文件名字为&lt;code&gt;qemu-system-xxx&lt;/code&gt;和 &lt;code&gt;qemu-xxx&lt;/code&gt;
本文使用如下配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;./configure --prefix=XXX --enable-debug --target-list=riscv32-softmmu,riscv32-linux-user,riscv64-linux-user,riscv64-softmmu --enable-kvm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# --prefix 选项设置qemu的安装位置绝对路径，之后若要卸载删除qemu只要删除该文件夹即可，--enable-kvm开启kvm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# config完，可以在指定的qemu安装文件夹下面找到config-host.mak文件，
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# 该文件记录着qemu配置的选项，可以和自己设置的进行对比，确保配置和自己已知
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着进行编译&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make -j8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;直接&lt;code&gt;make&lt;/code&gt;会很慢，第一次编译时默认安装说有模拟器，编译了三四个小时。加上&lt;code&gt;-j8&lt;/code&gt;可以进行多线程编译&lt;/p&gt;
&lt;h2 id=&#34;创建与使用&#34;&gt;创建与使用&lt;/h2&gt;
&lt;h3 id=&#34;创建虚拟镜像&#34;&gt;创建虚拟镜像&lt;/h3&gt;
&lt;p&gt;使用虚拟镜像来模拟虚拟机的硬盘，在启动虚拟机之前需要创建一个镜像文件&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# qemu-img create -f qcow2 qmtest.img 10G
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Formatting &amp;#39;qmtest.img&amp;#39;, fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# ls
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qmtest.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-f&lt;/code&gt;选项用于指定镜像的格式，&lt;code&gt;qcow2&lt;/code&gt;格式是 QEMU 最常用的镜像格式，采用写时复制技术来优化性能。&lt;code&gt;qmtest.img&lt;/code&gt;是镜像文件的名字，&lt;code&gt;10G&lt;/code&gt;是镜像文件大小。&lt;/p&gt;
&lt;p&gt;镜像文件创建完成后，可使用&lt;code&gt;qemu-system-x86&lt;/code&gt;来启动&lt;code&gt;x86&lt;/code&gt;架构的虚拟机：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-x86_64 qmtest.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;qmtest.img 中还未安装操作系统，所以会提示“No bootable device”的错误。&lt;/p&gt;
&lt;h3 id=&#34;准备操作系统镜像&#34;&gt;准备操作系统镜像&lt;/h3&gt;
&lt;p&gt;下载需要的 Linux 发行版镜像文件，&lt;a href=&#34;https://launchpad.net/ubuntu/+cdmirrors&#34;&gt;https://launchpad.net/ubuntu/+cdmirrors&lt;/a&gt;，找到想要下载的镜像，这里以交通大学的镜像为例
右击链接复制地址：&lt;a href=&#34;https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso&#34;&gt;https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# wget https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;检查-kvm-是否可用&#34;&gt;检查 KVM 是否可用&lt;/h3&gt;
&lt;p&gt;QEMU 使用 KVM 来提升虚拟机性能，如果不启用 KVM 会导致性能损失。要使用 KVM，首先要检查硬件是否有虚拟化支持：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# grep -E &amp;#39;vmx|svm&amp;#39; /proc/cpuinfo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果有输出则表示硬件有虚拟化支持。其次要检查 kvm 模块是否已经加载：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# lsmod | grep kvm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kvm_intel             142999  0 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kvm                   444314  1 kvm_intel
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果&lt;code&gt;kvm_intel/kvm_amd&lt;/code&gt;、&lt;code&gt;kvm&lt;/code&gt;模块被显示出来，则&lt;code&gt;kvm&lt;/code&gt;模块已经加载。最后要确保 qemu 在编译的时候使能了&lt;code&gt;KVM&lt;/code&gt;，即在执行&lt;code&gt;configure&lt;/code&gt;脚本的时候加入了&lt;code&gt;–enable-kvm&lt;/code&gt;选项。&lt;/p&gt;
&lt;h3 id=&#34;启动虚拟机安装操作系统&#34;&gt;启动虚拟机安装操作系统&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# qemu-system-x86_64 -m 2048 -enable-kvm qmtest.img -cdrom ./Fedora-Live-Desktop-x86_64-20-1.iso
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-m&lt;/code&gt;指定虚拟机内存大小，默认单位是 MB，&lt;code&gt;-enable-kvm&lt;/code&gt;使用 KVM 进行加速，&lt;code&gt;-cdrom&lt;/code&gt;添加 fedora 的安装镜像。可在弹出的窗口中操作虚拟机，安装操作系统，安装完成后重起虚拟机便会从硬盘 (qmtest.img) 启动。之后再启动虚拟机只需要执行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/#  qemu-system-x86_64 -m 2048 -enable-kvm qmtest.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;退出-qemu&#34;&gt;退出 qemu&lt;/h2&gt;
&lt;p&gt;在运行 qemu 后，关闭图形界面但是终端仍然是处于 qemu 环境中，可以直接关闭终端退出。如果不想关闭终端，可以另外打开一个终端 kill 进程&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;killall qemu-system-riscv32
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果记不清全称，可以输入大概名称回车后会列出相关的进程&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="简介">简介</h2>
<p>QEMU 是一款开源的模拟器及虚拟机监管器 (Virtual Machine Monitor, VMM)。QEMU 主要提供两种功能给用户使用。一是作为用户态模拟器，利用动态代码翻译机制来执行不同于主机架构的代码。二是作为虚拟机监管器，模拟全系统，利用其他 VMM(Xen, KVM, etc) 来使用硬件提供的虚拟化支持，创建接近于主机性能的虚拟机。</p>
<h2 id="安装">安装</h2>
<h3 id="使用包管理安装">使用包管理安装</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">sudo apt-get install qemu
</span></span></code></pre></div><h3 id="使用源码安装">使用源码安装</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">wget</span> <span class="n">wget</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">download</span><span class="o">.</span><span class="n">qemu</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">qemu</span><span class="o">-</span><span class="mf">6.1</span><span class="o">.</span><span class="mi">0</span><span class="o">-</span><span class="n">rc3</span><span class="o">.</span><span class="n">tar</span><span class="o">.</span><span class="n">xz</span>
</span></span><span class="line"><span class="cl"><span class="n">tar</span> <span class="n">xvJf</span> <span class="n">qemu</span><span class="o">-</span><span class="mf">6.1</span><span class="o">.</span><span class="mi">0</span><span class="o">-</span><span class="n">rc3</span><span class="o">.</span><span class="n">tar</span><span class="o">.</span><span class="n">xz</span>
</span></span><span class="line"><span class="cl"><span class="n">cd</span> <span class="n">qemu</span><span class="o">-</span><span class="mf">6.1</span><span class="o">.</span><span class="mi">0</span><span class="o">-</span><span class="n">rc3</span>
</span></span></code></pre></div><h3 id="安装相关库">安装相关库</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">apt-get install libglib2.0-dev
</span></span><span class="line"><span class="cl">apt-get install ninja-build
</span></span><span class="line"><span class="cl">apt install g++
</span></span><span class="line"><span class="cl">apt install libpixman-1-dev
</span></span><span class="line"><span class="cl">apt install libsdl2-dev -y
</span></span></code></pre></div><h3 id="配置">配置</h3>
<p>通过<code>./configure --help</code> 的查看编译时的选项，<code>--target-list</code>选项为可选的模拟器，默认全选。
<code>--target-list</code> 中的 <code>xxx-soft</code> 和 <code>xxx-linux-user</code> 分别指系统模拟器和应用程序模拟器，生成的二进制文件名字为<code>qemu-system-xxx</code>和 <code>qemu-xxx</code>
本文使用如下配置：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">./configure --prefix=XXX --enable-debug --target-list=riscv32-softmmu,riscv32-linux-user,riscv64-linux-user,riscv64-softmmu --enable-kvm
</span></span><span class="line"><span class="cl"># --prefix 选项设置qemu的安装位置绝对路径，之后若要卸载删除qemu只要删除该文件夹即可，--enable-kvm开启kvm
</span></span><span class="line"><span class="cl"># config完，可以在指定的qemu安装文件夹下面找到config-host.mak文件，
</span></span><span class="line"><span class="cl"># 该文件记录着qemu配置的选项，可以和自己设置的进行对比，确保配置和自己已知
</span></span></code></pre></div><p>接着进行编译</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">make -j8
</span></span></code></pre></div><p>直接<code>make</code>会很慢，第一次编译时默认安装说有模拟器，编译了三四个小时。加上<code>-j8</code>可以进行多线程编译</p>
<h2 id="创建与使用">创建与使用</h2>
<h3 id="创建虚拟镜像">创建虚拟镜像</h3>
<p>使用虚拟镜像来模拟虚拟机的硬盘，在启动虚拟机之前需要创建一个镜像文件</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# qemu-img create -f qcow2 qmtest.img 10G
</span></span><span class="line"><span class="cl">Formatting &#39;qmtest.img&#39;, fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off 
</span></span><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# ls
</span></span><span class="line"><span class="cl">qmtest.img
</span></span></code></pre></div><p><code>-f</code>选项用于指定镜像的格式，<code>qcow2</code>格式是 QEMU 最常用的镜像格式，采用写时复制技术来优化性能。<code>qmtest.img</code>是镜像文件的名字，<code>10G</code>是镜像文件大小。</p>
<p>镜像文件创建完成后，可使用<code>qemu-system-x86</code>来启动<code>x86</code>架构的虚拟机：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-system-x86_64 qmtest.img
</span></span></code></pre></div><p>qmtest.img 中还未安装操作系统，所以会提示“No bootable device”的错误。</p>
<h3 id="准备操作系统镜像">准备操作系统镜像</h3>
<p>下载需要的 Linux 发行版镜像文件，<a href="https://launchpad.net/ubuntu/+cdmirrors">https://launchpad.net/ubuntu/+cdmirrors</a>，找到想要下载的镜像，这里以交通大学的镜像为例
右击链接复制地址：<a href="https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso">https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# wget https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso
</span></span></code></pre></div><h3 id="检查-kvm-是否可用">检查 KVM 是否可用</h3>
<p>QEMU 使用 KVM 来提升虚拟机性能，如果不启用 KVM 会导致性能损失。要使用 KVM，首先要检查硬件是否有虚拟化支持：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# grep -E &#39;vmx|svm&#39; /proc/cpuinfo
</span></span></code></pre></div><p>如果有输出则表示硬件有虚拟化支持。其次要检查 kvm 模块是否已经加载：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# lsmod | grep kvm
</span></span><span class="line"><span class="cl">kvm_intel             142999  0 
</span></span><span class="line"><span class="cl">kvm                   444314  1 kvm_intel
</span></span></code></pre></div><p>如果<code>kvm_intel/kvm_amd</code>、<code>kvm</code>模块被显示出来，则<code>kvm</code>模块已经加载。最后要确保 qemu 在编译的时候使能了<code>KVM</code>，即在执行<code>configure</code>脚本的时候加入了<code>–enable-kvm</code>选项。</p>
<h3 id="启动虚拟机安装操作系统">启动虚拟机安装操作系统</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# qemu-system-x86_64 -m 2048 -enable-kvm qmtest.img -cdrom ./Fedora-Live-Desktop-x86_64-20-1.iso
</span></span></code></pre></div><p><code>-m</code>指定虚拟机内存大小，默认单位是 MB，<code>-enable-kvm</code>使用 KVM 进行加速，<code>-cdrom</code>添加 fedora 的安装镜像。可在弹出的窗口中操作虚拟机，安装操作系统，安装完成后重起虚拟机便会从硬盘 (qmtest.img) 启动。之后再启动虚拟机只需要执行：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/#  qemu-system-x86_64 -m 2048 -enable-kvm qmtest.img
</span></span></code></pre></div><h2 id="退出-qemu">退出 qemu</h2>
<p>在运行 qemu 后，关闭图形界面但是终端仍然是处于 qemu 环境中，可以直接关闭终端退出。如果不想关闭终端，可以另外打开一个终端 kill 进程</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">killall qemu-system-riscv32
</span></span></code></pre></div><p>如果记不清全称，可以输入大概名称回车后会列出相关的进程</p>
]]></content:encoded>
    </item>
    <item>
      <title>什么是驱动，驱动的作用又是什么？</title>
      <link>https://lifeislife.cn/posts/%E4%BB%80%E4%B9%88%E6%98%AF%E9%A9%B1%E5%8A%A8%E9%A9%B1%E5%8A%A8%E7%9A%84%E4%BD%9C%E7%94%A8%E5%8F%88%E6%98%AF%E4%BB%80%E4%B9%88/</link>
      <pubDate>Wed, 21 Jul 2021 15:02:58 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/%E4%BB%80%E4%B9%88%E6%98%AF%E9%A9%B1%E5%8A%A8%E9%A9%B1%E5%8A%A8%E7%9A%84%E4%BD%9C%E7%94%A8%E5%8F%88%E6%98%AF%E4%BB%80%E4%B9%88/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;任何一个计算机系统的运行都是系统中软硬件协作的结果，没有硬件的软件是空中楼阁，而没有软件的硬件则只是一堆废铁。&amp;ndash;&lt;a href=&#34;https://blog.csdn.net/yunfenglw/article/details/39337343&#34;&gt;天朗 - 星空&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;硬件是底层基础，所有软件代码的运行平台，相对固定不易改变，而软件是具体的应用，它灵活多变，可以应对用户的不同需求。&lt;/p&gt;
&lt;p&gt;为尽可能快速地完成设计，应用软件工程师不想也不必关心硬件，而硬件工程师也难有足够的闲暇和能力来顾忌软件。譬如，应用软件工程师在调用套接字发送和接收数据包的时候，不必关心网卡上的寄存器、存储空间、I/O 端口、片选以及其他任何硬件层面的操作调度；在使用&lt;code&gt;printf()&lt;/code&gt;函数输出信息的时候，他不用知道底层究竟是怎样把相应的信息输出到屏幕或者串口的具体硬件过程，需要的只是出现相应的显示效果。&lt;/p&gt;
&lt;p&gt;也就是说，应用软件工程师需要看到一个没有硬件的纯粹的软件世界，硬件必须被透明地呈现给他们。谁来实现硬件对应用软件工程师的隐形？这个艰巨的任务就落在了驱动工程师的头上。&lt;/p&gt;
&lt;p&gt;对设备驱动最通俗的解释就是“驱使硬件设备行动” 。设备驱动与底层硬件直接打交道，按照硬件设备的具体工作方式读写设备寄存器，完成设备的轮询、中断处理、DMA 通信，进行物理内存向虚拟内存的映射，最终使通信设备能够收发数据，使显示设备能够显示文字和画面，使存储设备能够记录文件和数据。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<blockquote>
<p>任何一个计算机系统的运行都是系统中软硬件协作的结果，没有硬件的软件是空中楼阁，而没有软件的硬件则只是一堆废铁。&ndash;<a href="https://blog.csdn.net/yunfenglw/article/details/39337343">天朗 - 星空</a></p>
</blockquote>
<p>硬件是底层基础，所有软件代码的运行平台，相对固定不易改变，而软件是具体的应用，它灵活多变，可以应对用户的不同需求。</p>
<p>为尽可能快速地完成设计，应用软件工程师不想也不必关心硬件，而硬件工程师也难有足够的闲暇和能力来顾忌软件。譬如，应用软件工程师在调用套接字发送和接收数据包的时候，不必关心网卡上的寄存器、存储空间、I/O 端口、片选以及其他任何硬件层面的操作调度；在使用<code>printf()</code>函数输出信息的时候，他不用知道底层究竟是怎样把相应的信息输出到屏幕或者串口的具体硬件过程，需要的只是出现相应的显示效果。</p>
<p>也就是说，应用软件工程师需要看到一个没有硬件的纯粹的软件世界，硬件必须被透明地呈现给他们。谁来实现硬件对应用软件工程师的隐形？这个艰巨的任务就落在了驱动工程师的头上。</p>
<p>对设备驱动最通俗的解释就是“驱使硬件设备行动” 。设备驱动与底层硬件直接打交道，按照硬件设备的具体工作方式读写设备寄存器，完成设备的轮询、中断处理、DMA 通信，进行物理内存向虚拟内存的映射，最终使通信设备能够收发数据，使显示设备能够显示文字和画面，使存储设备能够记录文件和数据。</p>
]]></content:encoded>
    </item>
    <item>
      <title>QEMU 学习记录</title>
      <link>https://lifeislife.cn/posts/qemu%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/</link>
      <pubDate>Tue, 20 Jul 2021 16:51:34 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/</guid>
      <description>&lt;h1 id=&#34;qemu-学习记录&#34;&gt;QEMU 学习记录&lt;/h1&gt;
&lt;h2 id=&#34;什么是-kvm&#34;&gt;什么是 KVM？&lt;/h2&gt;
&lt;p&gt;基于内核的虚拟机 &lt;code&gt;Kernel-based Virtual Machine（KVM）&lt;/code&gt;是一种内建于 Linux 中的开源虚拟化技术。具体而言，&lt;code&gt;KVM&lt;/code&gt; 可帮助用户将 Linux 转变为虚拟机监控程序，使主机计算机能够运行多个隔离的虚拟环境，即虚拟客户机或虚拟机（VM）。&lt;/p&gt;
&lt;h2 id=&#34;什么是-qemu&#34;&gt;什么是 QEMU？&lt;/h2&gt;
&lt;p&gt;Qemu 是一个完整的可以单独运行的软件，它可以用来模拟不同架构的机器，非常灵活和可移植。它主要通过一个特殊的&amp;rsquo;重编译器&amp;rsquo;将为特定处理器编写二进制代码转换为另一种。&lt;/p&gt;
&lt;h2 id=&#34;kvm-与-qemu-的关系&#34;&gt;KVM 与 QEMU 的关系&lt;/h2&gt;
&lt;p&gt;KVM 是 Linux 的一个模块。可以用&lt;code&gt;modprobe&lt;/code&gt;去加载 KVM 模块。加载了模块后，才能进一步通过其他工具创建虚拟机。但仅有 KVM 模块是 远远不够的，因为用户无法直接控制内核模块去作事情：还必须有一个用户空间的工具才行。这个用户空间的工具，开发者选择了已经成型的开源虚拟化软件 QEMU。KVM 使用了 QEMU 的一部分，并稍加改造，就成了可控制 KVM 的用户空间工具了。所以你会看到，官方提供的 KVM 下载有两 大部分三个文件，分别是 KVM 模块、QEMU 工具以及二者的合集。也就是说，你可以只升级 KVM 模块，也可以只升级 QEMU 工具。&lt;/p&gt;
&lt;h2 id=&#34;qemu-用户模式与系统模式&#34;&gt;QEMU 用户模式与系统模式&lt;/h2&gt;
&lt;p&gt;QEMU 属于应用层的仿真程序，它支持两种操作模式：&lt;strong&gt;用户模式&lt;/strong&gt;模拟和&lt;strong&gt;系统模式&lt;/strong&gt;模拟。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;用户模式仿真&lt;/strong&gt; 利用动态代码翻译机制，可以在当前 CPU 上执行被编译为支持其他 CPU 的程序，如可以在 x86 机器上执行一个 ARM 二进制可执行程序。（执行主机 CPU 指令的动态翻译并相应地转换 Linux 系统调用）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统模式仿真&lt;/strong&gt; 利用其它 VMM(Xen, KVM) 来使用硬件提供的虚拟化支持，创建接近于主机性能的全功能虚拟机，包括处理器和配套的外围设备（磁盘，以太网等）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;用户模式&#34;&gt;用户模式&lt;/h3&gt;
&lt;p&gt;支持的 CPU：x86 (32 and 64 bit), PowerPC (32 and 64 bit), ARM, MIPS (32 bit only), Sparc (32 and 64 bit), Alpha, ColdFire(m68k), CRISv32 和 MicroBlaze
下列操作系统支持 QEMU 的用户模式模拟：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linux (referred as qemu-linux-user)&lt;/li&gt;
&lt;li&gt;BSD (referred as qemu-bsd-user)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;调用（&lt;a href=&#34;https://qemu.readthedocs.io/en/latest/user/main.html&#34;&gt;具体参数含义&lt;/a&gt;）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] [-R size] program [arguments...]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用户模式模拟环境下运行速度要比系统模式模拟环境下快，但并不是完美模拟，比如程序读取&lt;code&gt;/proc/cpuinfo&lt;/code&gt;内容时，由主机内核返回，因此返回的信息是描述主机 CPU 的，而不是模拟的 CPU。&lt;/p&gt;
&lt;h3 id=&#34;系统模式&#34;&gt;系统模式&lt;/h3&gt;
&lt;p&gt;首先创建虚拟镜像，模拟硬盘空间：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# qemu-img create -f qcow2 qmtest.img 10G
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Formatting &amp;#39;qmtest.img&amp;#39;, fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# ls
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qmtest.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-f&lt;/code&gt;选项用于指定镜像的格式，&lt;code&gt;qcow2&lt;/code&gt;格式是 QEMU 最常用的镜像格式，采用写时复制技术来优化性能。&lt;code&gt;qmtest.img&lt;/code&gt;是镜像文件的名字，&lt;code&gt;10G&lt;/code&gt;是镜像文件大小。&lt;/p&gt;
&lt;p&gt;镜像文件创建完成后，可使用&lt;code&gt;qemu-system-x86&lt;/code&gt;来启动&lt;code&gt;x86&lt;/code&gt;架构的虚拟机：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-system-x86_64 qmtest.img
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;qmtest.img 中还未安装操作系统，所以会提示“No bootable device”的错误。&lt;/p&gt;
&lt;p&gt;其次，准备操作系统镜像
下载需要的 Linux 发行版镜像文件，&lt;a href=&#34;https://launchpad.net/ubuntu/+cdmirrors&#34;&gt;https://launchpad.net/ubuntu/+cdmirrors&lt;/a&gt;，找到想要下载的镜像，这里以交通大学的镜像为例
右击链接复制地址：&lt;a href=&#34;https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso&#34;&gt;https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# wget https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后，启动虚拟机安装操作系统&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;root@hanhan:/home/dominic/qemu/# qemu-system-x86_64 -m 2048 -enable-kvm qmtest.img -cdrom ./Fedora-Live-Desktop-x86_64-20-1.iso
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;-m&lt;/code&gt;指定虚拟机内存大小，默认单位是 MB，&lt;code&gt;-enable-kvm&lt;/code&gt;使用 KVM 进行加速，&lt;code&gt;-cdrom&lt;/code&gt;添加 fedora 的安装镜像。&lt;/p&gt;
&lt;p&gt;该模式下，要比用户模式模拟慢得多，因为模拟了目标内核，以及设备输入/输出、中断等。&lt;/p&gt;
&lt;h2 id=&#34;qemu-工作原理&#34;&gt;QEMU 工作原理&lt;/h2&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721140349.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721140349.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
单纯使用 qemu，采用的是完全虚拟化的模式。qemu 向 Guest OS 模拟 CPU，也模拟其他的硬件，GuestOS 认为自己和硬件直接打交道，其实是同 qemu 模拟出来的硬件打交道，qemu 会将这些指令转译给真正的硬件。由于所有的指令都要从 qemu 里面过一手，因而性能就会比较差。&lt;/p&gt;
&lt;p&gt;完全虚拟化是非常慢的，所以要使用硬件辅助虚拟化技术 &lt;code&gt;Intel-VT&lt;/code&gt;，&lt;code&gt;AMD-V&lt;/code&gt;，所以需要 CPU 硬件开启这个标志位，一般在 BIOS 里面设置。当确认开始了标志位之后，通过&lt;code&gt;KVM&lt;/code&gt;，GuestOS 的 CPU 指令不用经过 Qemu 转译，直接运行，大大提高了速度。所以，&lt;code&gt;KVM&lt;/code&gt; 在内核里面需要有一个模块，来设置当前 CPU 是 Guest OS 在用，还是 Host OS 在用。&lt;/p&gt;
&lt;p&gt;可以通过如下命令查看内核模块中是否有 KVM&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;lsmod | grep kvm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;KVM 内核模块通过 &lt;code&gt;/dev/kvm&lt;/code&gt; 暴露接口，用户态程序可以通过 &lt;code&gt;ioctl&lt;/code&gt;来访问这个接口。Qemu 将 KVM 整合进来，将有关 CPU 指令的部分交由内核模块来做，就是 &lt;code&gt;qemu-kvm (qemu-system-XXX)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;qemu 和 kvm 整合之后，CPU 的性能问题解决了。另外 Qemu 还会模拟其他的硬件，如网络和硬盘。同样，全虚拟化的方式也会影响这些设备的性能。&lt;/p&gt;
&lt;p&gt;于是，qemu 采取半虚拟化的方式，让 Guest OS 加载特殊的驱动来做这件事情。&lt;/p&gt;
&lt;p&gt;例如，网络需要加载 &lt;code&gt;virtio_net&lt;/code&gt;，存储需要加载 &lt;code&gt;virtio_blk&lt;/code&gt;，Guest 需要安装这些半虚拟化驱动，GuestOS 知道自己是虚拟机，所以数据会直接发送给半虚拟化设备，经过特殊处理（例如排队、缓存、批量处理等性能优化方式），最终发送给真正的硬件。这在一定程度上提高了性能。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Q : 系统模式和用户模式的区别？
系统模式 是 qemu 虚拟出一套完整的硬件环境，包含 CPU，内存，网卡，硬盘，对于虚拟机上运行的 OS 看到的和硬件和真实的是一样的。
用户模式是直接将可执行的文件进行指令翻译，只虚拟出 CPU。
假设有 KVM：host 是 x86，QEMU 虚拟出 x86 的系统模式 运行 Windows 系统。QEMU 会将 Windows 指令直接交给  host CPU 直接运行（这个功能是由 KVM 实现的，相当于直接调用 host CPU），性能损失小。内存，硬盘，网络等外设是由 qemu 虚拟出来的。
假设无 KVM：host 是 x86，QEMU 虚拟出 x86 的系统模式运行 Windows 系统。QEMU 会将 Windows 指令翻译成中间码，中间码再转成   host CPU 指令（这个功能是由 qemu TCG 实现的），性能损失大。内存，硬盘，网洛等外设是由 qemu 虚拟出来的。
假设有 KVM：host 是 x86，QEMU 虚拟出 RISC-V 的系统模式 运行 Linux 系统。QEMU 会将 Linux 指令翻译成中间码，中间码再转成 host CPU 指令（这个功能是由 qemu TCG 实现的），性能损失大。内存，硬盘，网洛等外设是由 qemu 虚拟出来的。
KVM 需要在虚拟机与宿主机架构相同时才生效。
此外，用户模式下调用 IO 硬件会报错。qemu 系统模式下会模拟出所有设备，但是模拟的 IO 设备效率低，所以后来有了半虚拟化。&lt;/p&gt;
&lt;/blockquote&gt;
</description>
      <content:encoded><![CDATA[<h1 id="qemu-学习记录">QEMU 学习记录</h1>
<h2 id="什么是-kvm">什么是 KVM？</h2>
<p>基于内核的虚拟机 <code>Kernel-based Virtual Machine（KVM）</code>是一种内建于 Linux 中的开源虚拟化技术。具体而言，<code>KVM</code> 可帮助用户将 Linux 转变为虚拟机监控程序，使主机计算机能够运行多个隔离的虚拟环境，即虚拟客户机或虚拟机（VM）。</p>
<h2 id="什么是-qemu">什么是 QEMU？</h2>
<p>Qemu 是一个完整的可以单独运行的软件，它可以用来模拟不同架构的机器，非常灵活和可移植。它主要通过一个特殊的&rsquo;重编译器&rsquo;将为特定处理器编写二进制代码转换为另一种。</p>
<h2 id="kvm-与-qemu-的关系">KVM 与 QEMU 的关系</h2>
<p>KVM 是 Linux 的一个模块。可以用<code>modprobe</code>去加载 KVM 模块。加载了模块后，才能进一步通过其他工具创建虚拟机。但仅有 KVM 模块是 远远不够的，因为用户无法直接控制内核模块去作事情：还必须有一个用户空间的工具才行。这个用户空间的工具，开发者选择了已经成型的开源虚拟化软件 QEMU。KVM 使用了 QEMU 的一部分，并稍加改造，就成了可控制 KVM 的用户空间工具了。所以你会看到，官方提供的 KVM 下载有两 大部分三个文件，分别是 KVM 模块、QEMU 工具以及二者的合集。也就是说，你可以只升级 KVM 模块，也可以只升级 QEMU 工具。</p>
<h2 id="qemu-用户模式与系统模式">QEMU 用户模式与系统模式</h2>
<p>QEMU 属于应用层的仿真程序，它支持两种操作模式：<strong>用户模式</strong>模拟和<strong>系统模式</strong>模拟。</p>
<ul>
<li><strong>用户模式仿真</strong> 利用动态代码翻译机制，可以在当前 CPU 上执行被编译为支持其他 CPU 的程序，如可以在 x86 机器上执行一个 ARM 二进制可执行程序。（执行主机 CPU 指令的动态翻译并相应地转换 Linux 系统调用）。</li>
<li><strong>系统模式仿真</strong> 利用其它 VMM(Xen, KVM) 来使用硬件提供的虚拟化支持，创建接近于主机性能的全功能虚拟机，包括处理器和配套的外围设备（磁盘，以太网等）。</li>
</ul>
<h3 id="用户模式">用户模式</h3>
<p>支持的 CPU：x86 (32 and 64 bit), PowerPC (32 and 64 bit), ARM, MIPS (32 bit only), Sparc (32 and 64 bit), Alpha, ColdFire(m68k), CRISv32 和 MicroBlaze
下列操作系统支持 QEMU 的用户模式模拟：</p>
<ul>
<li>Linux (referred as qemu-linux-user)</li>
<li>BSD (referred as qemu-bsd-user)</li>
</ul>
<p>调用（<a href="https://qemu.readthedocs.io/en/latest/user/main.html">具体参数含义</a>）</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] [-R size] program [arguments...]
</span></span></code></pre></div><p>用户模式模拟环境下运行速度要比系统模式模拟环境下快，但并不是完美模拟，比如程序读取<code>/proc/cpuinfo</code>内容时，由主机内核返回，因此返回的信息是描述主机 CPU 的，而不是模拟的 CPU。</p>
<h3 id="系统模式">系统模式</h3>
<p>首先创建虚拟镜像，模拟硬盘空间：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# qemu-img create -f qcow2 qmtest.img 10G
</span></span><span class="line"><span class="cl">Formatting &#39;qmtest.img&#39;, fmt=qcow2 size=10737418240 encryption=off cluster_size=65536 lazy_refcounts=off 
</span></span><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# ls
</span></span><span class="line"><span class="cl">qmtest.img
</span></span></code></pre></div><p><code>-f</code>选项用于指定镜像的格式，<code>qcow2</code>格式是 QEMU 最常用的镜像格式，采用写时复制技术来优化性能。<code>qmtest.img</code>是镜像文件的名字，<code>10G</code>是镜像文件大小。</p>
<p>镜像文件创建完成后，可使用<code>qemu-system-x86</code>来启动<code>x86</code>架构的虚拟机：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">qemu-system-x86_64 qmtest.img
</span></span></code></pre></div><p>qmtest.img 中还未安装操作系统，所以会提示“No bootable device”的错误。</p>
<p>其次，准备操作系统镜像
下载需要的 Linux 发行版镜像文件，<a href="https://launchpad.net/ubuntu/+cdmirrors">https://launchpad.net/ubuntu/+cdmirrors</a>，找到想要下载的镜像，这里以交通大学的镜像为例
右击链接复制地址：<a href="https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso">https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# wget https://ftp.sjtu.edu.cn/ubuntu-cd/20.10/ubuntu-20.10-live-server-amd64.iso
</span></span></code></pre></div><p>最后，启动虚拟机安装操作系统</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">root@hanhan:/home/dominic/qemu/# qemu-system-x86_64 -m 2048 -enable-kvm qmtest.img -cdrom ./Fedora-Live-Desktop-x86_64-20-1.iso
</span></span></code></pre></div><p><code>-m</code>指定虚拟机内存大小，默认单位是 MB，<code>-enable-kvm</code>使用 KVM 进行加速，<code>-cdrom</code>添加 fedora 的安装镜像。</p>
<p>该模式下，要比用户模式模拟慢得多，因为模拟了目标内核，以及设备输入/输出、中断等。</p>
<h2 id="qemu-工作原理">QEMU 工作原理</h2>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721140349.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210721140349.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>
单纯使用 qemu，采用的是完全虚拟化的模式。qemu 向 Guest OS 模拟 CPU，也模拟其他的硬件，GuestOS 认为自己和硬件直接打交道，其实是同 qemu 模拟出来的硬件打交道，qemu 会将这些指令转译给真正的硬件。由于所有的指令都要从 qemu 里面过一手，因而性能就会比较差。</p>
<p>完全虚拟化是非常慢的，所以要使用硬件辅助虚拟化技术 <code>Intel-VT</code>，<code>AMD-V</code>，所以需要 CPU 硬件开启这个标志位，一般在 BIOS 里面设置。当确认开始了标志位之后，通过<code>KVM</code>，GuestOS 的 CPU 指令不用经过 Qemu 转译，直接运行，大大提高了速度。所以，<code>KVM</code> 在内核里面需要有一个模块，来设置当前 CPU 是 Guest OS 在用，还是 Host OS 在用。</p>
<p>可以通过如下命令查看内核模块中是否有 KVM</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">lsmod | grep kvm
</span></span></code></pre></div><p>KVM 内核模块通过 <code>/dev/kvm</code> 暴露接口，用户态程序可以通过 <code>ioctl</code>来访问这个接口。Qemu 将 KVM 整合进来，将有关 CPU 指令的部分交由内核模块来做，就是 <code>qemu-kvm (qemu-system-XXX)</code>。</p>
<p>qemu 和 kvm 整合之后，CPU 的性能问题解决了。另外 Qemu 还会模拟其他的硬件，如网络和硬盘。同样，全虚拟化的方式也会影响这些设备的性能。</p>
<p>于是，qemu 采取半虚拟化的方式，让 Guest OS 加载特殊的驱动来做这件事情。</p>
<p>例如，网络需要加载 <code>virtio_net</code>，存储需要加载 <code>virtio_blk</code>，Guest 需要安装这些半虚拟化驱动，GuestOS 知道自己是虚拟机，所以数据会直接发送给半虚拟化设备，经过特殊处理（例如排队、缓存、批量处理等性能优化方式），最终发送给真正的硬件。这在一定程度上提高了性能。</p>
<blockquote>
<p>Q : 系统模式和用户模式的区别？
系统模式 是 qemu 虚拟出一套完整的硬件环境，包含 CPU，内存，网卡，硬盘，对于虚拟机上运行的 OS 看到的和硬件和真实的是一样的。
用户模式是直接将可执行的文件进行指令翻译，只虚拟出 CPU。
假设有 KVM：host 是 x86，QEMU 虚拟出 x86 的系统模式 运行 Windows 系统。QEMU 会将 Windows 指令直接交给  host CPU 直接运行（这个功能是由 KVM 实现的，相当于直接调用 host CPU），性能损失小。内存，硬盘，网络等外设是由 qemu 虚拟出来的。
假设无 KVM：host 是 x86，QEMU 虚拟出 x86 的系统模式运行 Windows 系统。QEMU 会将 Windows 指令翻译成中间码，中间码再转成   host CPU 指令（这个功能是由 qemu TCG 实现的），性能损失大。内存，硬盘，网洛等外设是由 qemu 虚拟出来的。
假设有 KVM：host 是 x86，QEMU 虚拟出 RISC-V 的系统模式 运行 Linux 系统。QEMU 会将 Linux 指令翻译成中间码，中间码再转成 host CPU 指令（这个功能是由 qemu TCG 实现的），性能损失大。内存，硬盘，网洛等外设是由 qemu 虚拟出来的。
KVM 需要在虚拟机与宿主机架构相同时才生效。
此外，用户模式下调用 IO 硬件会报错。qemu 系统模式下会模拟出所有设备，但是模拟的 IO 设备效率低，所以后来有了半虚拟化。</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>ZH-Unix 是什么，为什么重要？</title>
      <link>https://lifeislife.cn/posts/zh-unix%E6%98%AF%E4%BB%80%E4%B9%88%E4%B8%BA%E4%BB%80%E4%B9%88%E9%87%8D%E8%A6%81/</link>
      <pubDate>Tue, 20 Jul 2021 15:44:05 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/zh-unix%E6%98%AF%E4%BB%80%E4%B9%88%E4%B8%BA%E4%BB%80%E4%B9%88%E9%87%8D%E8%A6%81/</guid>
      <description>&lt;h1 id=&#34;unix-是什么为什么重要&#34;&gt;Unix 是什么，为什么重要？&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Author：CHRIS HOFFMAN
译：&lt;a href=&#34;https://www.howtogeek.com/182649/htg-explains-what-is-unix/&#34;&gt;What Is Unix, and Why Does It Matter?&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;大多数操作系统都可以分为两大类。除了微软基于 Windows NT 的操作系统之外，几乎所有其他系统的祖宗都是 Unix。&lt;/p&gt;
&lt;p&gt;Linux、Mac OS X、Android、iOS、Chrome OS、PlayStation 4 上使用的 Orbis 操作系统，无论路由器上运行的是什么固件——所有这些操作系统通常都被称为“类 Unix”操作系统。&lt;/p&gt;
&lt;h2 id=&#34;unix-的设计延续至今&#34;&gt;Unix 的设计延续至今&lt;/h2&gt;
&lt;p&gt;19 世纪中后期 Unix 在贝尔实验室中被开发出来。最初版的 Unix 有许多重要的设计特性至今仍然在使用。&lt;/p&gt;
&lt;p&gt;“Unix 哲学”之一就是，创建小型、模块化的程序，一个程序只做一件事并把它做好。如果你经常使用 Linux 终端，那么你应该对此很熟悉——系统提供了许多实用程序，这些程序可以通过管道和其他功能以不同方式组合以执行更复杂的任务。甚至图形程序也可能在后台调用更简单的实用程序来完成复杂的工作。这也使得创建 shell 脚本变得容易，将简单的工具串在一起来完成复杂的事情。&lt;/p&gt;
&lt;p&gt;Unix 有一个程序之间通信用的单一文件系统。这就是为什么在 Linux 上“一切都是文件” ——包括硬件设备和提供系统信息或其他数据的特殊文件。这也是为什么只有 Windows 有驱动器号（C、D、E 盘）的原因，它是从 DOS 继承的——在其他操作系统上，系统上的每个文件都是单个目录层次结构的一部分。&lt;/p&gt;
&lt;h2 id=&#34;追寻-unix-的后代&#34;&gt;追寻 Unix 的后代&lt;/h2&gt;
&lt;p&gt;Unix 及其后代的历史错综复杂，简化起见，我们大致将 Unix 的后代分为两类。&lt;/p&gt;
&lt;p&gt;一类 Unix 后代是在学术界发展起来的。第一个是 BSD（BerkeleySoftwareDistribution），一个开源、类 Unix 操作系统。BSD 通过 FreeBSD、NetBSD 和 OpenBSD 延续至今。NeXTStep 也是基于最初的 BSD 开发的，Apple 的 Mac OS X 是基于 NeXTStep 开发出来的，而 iOS 则基于 Mac OS X。还有一些操作系统，包括 PlayStation 4 上使用的 Orbis OS，都是从 BSD 操作系统衍生而来的。&lt;/p&gt;
&lt;p&gt;Richard Stallman 的 GNU 项目也是为了应对 AT&amp;amp;T 日益严格的 Unix 软件许可条款而启动的。MINIX 是一个为教育目的而创建的类 Unix 操作系统，Linux 的灵感来自于 MINIX。我们今天所知道的 Linux 实际上是 GNU/Linux，因为它由 Linux 内核和许多 GNU 实用程序组成。GNU/Linux 并非直接继承自 BSD，但它继承了 Unix 的设计并植根于学术界。当今的许多操作系统，包括 Android、ChromeOS、SteamOS 以及大量设备的嵌入式操作系统，都基于 Linux。&lt;/p&gt;
&lt;p&gt;另一类就是商业 Unix 操作系统。AT&amp;amp;T UNIX、SCO UnixWare、Sun Microsystems Solaris、HP-UX、IBM AIX、SGI IRIX——许多大公司想要创建他们自己的 Unix 版本。这些在今天并不常见，但其中一些仍然存在。&lt;/p&gt;
&lt;h2 id=&#34;dos-和-windows-nt-的崛起&#34;&gt;DOS 和 Windows NT 的崛起&lt;/h2&gt;
&lt;p&gt;许多人期望 Unix 成为行业标准操作系统，但 DOS 系统和“IBM PC 兼容”的计算机最终流行起来。Microsoft 的 DOS 成为其中最成功的 DOS 系统。DOS 系统完全不同于 Unix，这就是为什么 Windows 使用反斜杠作为文件路径，而其他一切都使用正斜杠。这个决定是在 DOS 系统早期做出的，后来的 Windows 版本继承了它，就像 BSD、Linux、Mac OS X 和其他类 Unix 操作系统继承了许多 Unix 的设计一样。&lt;/p&gt;
&lt;p&gt;Windows 3.1、Windows 95、Windows 98 和 Windows ME 都基于底层的 DOS。当时，微软正在开发一种更现代、更稳定的操作系统，他们将其命名为 Windows NT——即“Windows  New Technology”。Windows NT 最终以 Windows XP 的形式出现在普通用户的计算机中，但在此之前，它以 Windows 2000 和 Windows NT 的形式供公司使用。&lt;/p&gt;
&lt;p&gt;今天，微软的所有操作系统都基于 Windows NT 内核。Windows 7、Windows 8、Windows RT、Windows Phone 8、Windows Server 和 Xbox One 的操作系统都使用 Windows NT 内核。与大多数其他操作系统不同，Windows NT 并不是作为类 Unix 操作系统开发的。&lt;/p&gt;
&lt;p&gt;当然，微软并不是完全重新开始。为了保持与 DOS 和旧的 Windows 软件的兼容性，Windows NT 继承了许多 DOS 约定，如驱动器号、文件路径的反斜杠和命令行的正斜杠。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“在绝大多数地方，用的都是/（slash），包括 Mac/Linux，也包括 URL。你唯一需要记住的是，Microsoft 这个怪鸡在自己的操作系统里面偏要用\（backslash），使得自己与众不同。
在 Windows 中，正斜杠/表示除法，用来进行整除运算；反斜杠\用来表示目录。
在 Unix 系统中，/表示目录；\表示跳脱字符将特殊字符变成一般字符
Windows由于使用斜杠/作为DOS命令提示符的参数标志了，为了不混淆，所以采用反斜杠\作为路径分隔符。所以目前windows系统上的文件浏览器都是用反斜杠\作为路径分隔符。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;为什么重要&#34;&gt;为什么重要？&lt;/h2&gt;
&lt;p&gt;你是否曾经看过 Mac OS X 终端或文件系统，并注意到它与 Linux 的相似之处，以及它们与 Windows 的不同之处？嗯，这就是为什么——Mac OSX 和 Linux 都是类 Unix 操作系统。&lt;/p&gt;
&lt;p&gt;了解这段历史有助于您了解什么是“类 Unix”操作系统，以及为什么这么多操作系统看起来彼此如此相似而 Windows 似乎如此不同。这解释了为什么 Linux 极客会觉得 Mac OS X 上的终端如此熟悉，而 Windows 上的命令提示符和 PowerShell 与其他命令行环境如此不同。&lt;/p&gt;
&lt;p&gt;这只是一个简短的历史，它将帮助您了解我们如何到达今天的位置，而不会陷入细节中。如果您想了解更多信息，可以找到有关 Unix 历史的整本书。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="unix-是什么为什么重要">Unix 是什么，为什么重要？</h1>
<blockquote>
<p>Author：CHRIS HOFFMAN
译：<a href="https://www.howtogeek.com/182649/htg-explains-what-is-unix/">What Is Unix, and Why Does It Matter?</a></p>
</blockquote>
<p>大多数操作系统都可以分为两大类。除了微软基于 Windows NT 的操作系统之外，几乎所有其他系统的祖宗都是 Unix。</p>
<p>Linux、Mac OS X、Android、iOS、Chrome OS、PlayStation 4 上使用的 Orbis 操作系统，无论路由器上运行的是什么固件——所有这些操作系统通常都被称为“类 Unix”操作系统。</p>
<h2 id="unix-的设计延续至今">Unix 的设计延续至今</h2>
<p>19 世纪中后期 Unix 在贝尔实验室中被开发出来。最初版的 Unix 有许多重要的设计特性至今仍然在使用。</p>
<p>“Unix 哲学”之一就是，创建小型、模块化的程序，一个程序只做一件事并把它做好。如果你经常使用 Linux 终端，那么你应该对此很熟悉——系统提供了许多实用程序，这些程序可以通过管道和其他功能以不同方式组合以执行更复杂的任务。甚至图形程序也可能在后台调用更简单的实用程序来完成复杂的工作。这也使得创建 shell 脚本变得容易，将简单的工具串在一起来完成复杂的事情。</p>
<p>Unix 有一个程序之间通信用的单一文件系统。这就是为什么在 Linux 上“一切都是文件” ——包括硬件设备和提供系统信息或其他数据的特殊文件。这也是为什么只有 Windows 有驱动器号（C、D、E 盘）的原因，它是从 DOS 继承的——在其他操作系统上，系统上的每个文件都是单个目录层次结构的一部分。</p>
<h2 id="追寻-unix-的后代">追寻 Unix 的后代</h2>
<p>Unix 及其后代的历史错综复杂，简化起见，我们大致将 Unix 的后代分为两类。</p>
<p>一类 Unix 后代是在学术界发展起来的。第一个是 BSD（BerkeleySoftwareDistribution），一个开源、类 Unix 操作系统。BSD 通过 FreeBSD、NetBSD 和 OpenBSD 延续至今。NeXTStep 也是基于最初的 BSD 开发的，Apple 的 Mac OS X 是基于 NeXTStep 开发出来的，而 iOS 则基于 Mac OS X。还有一些操作系统，包括 PlayStation 4 上使用的 Orbis OS，都是从 BSD 操作系统衍生而来的。</p>
<p>Richard Stallman 的 GNU 项目也是为了应对 AT&amp;T 日益严格的 Unix 软件许可条款而启动的。MINIX 是一个为教育目的而创建的类 Unix 操作系统，Linux 的灵感来自于 MINIX。我们今天所知道的 Linux 实际上是 GNU/Linux，因为它由 Linux 内核和许多 GNU 实用程序组成。GNU/Linux 并非直接继承自 BSD，但它继承了 Unix 的设计并植根于学术界。当今的许多操作系统，包括 Android、ChromeOS、SteamOS 以及大量设备的嵌入式操作系统，都基于 Linux。</p>
<p>另一类就是商业 Unix 操作系统。AT&amp;T UNIX、SCO UnixWare、Sun Microsystems Solaris、HP-UX、IBM AIX、SGI IRIX——许多大公司想要创建他们自己的 Unix 版本。这些在今天并不常见，但其中一些仍然存在。</p>
<h2 id="dos-和-windows-nt-的崛起">DOS 和 Windows NT 的崛起</h2>
<p>许多人期望 Unix 成为行业标准操作系统，但 DOS 系统和“IBM PC 兼容”的计算机最终流行起来。Microsoft 的 DOS 成为其中最成功的 DOS 系统。DOS 系统完全不同于 Unix，这就是为什么 Windows 使用反斜杠作为文件路径，而其他一切都使用正斜杠。这个决定是在 DOS 系统早期做出的，后来的 Windows 版本继承了它，就像 BSD、Linux、Mac OS X 和其他类 Unix 操作系统继承了许多 Unix 的设计一样。</p>
<p>Windows 3.1、Windows 95、Windows 98 和 Windows ME 都基于底层的 DOS。当时，微软正在开发一种更现代、更稳定的操作系统，他们将其命名为 Windows NT——即“Windows  New Technology”。Windows NT 最终以 Windows XP 的形式出现在普通用户的计算机中，但在此之前，它以 Windows 2000 和 Windows NT 的形式供公司使用。</p>
<p>今天，微软的所有操作系统都基于 Windows NT 内核。Windows 7、Windows 8、Windows RT、Windows Phone 8、Windows Server 和 Xbox One 的操作系统都使用 Windows NT 内核。与大多数其他操作系统不同，Windows NT 并不是作为类 Unix 操作系统开发的。</p>
<p>当然，微软并不是完全重新开始。为了保持与 DOS 和旧的 Windows 软件的兼容性，Windows NT 继承了许多 DOS 约定，如驱动器号、文件路径的反斜杠和命令行的正斜杠。</p>
<blockquote>
<p>“在绝大多数地方，用的都是/（slash），包括 Mac/Linux，也包括 URL。你唯一需要记住的是，Microsoft 这个怪鸡在自己的操作系统里面偏要用\（backslash），使得自己与众不同。
在 Windows 中，正斜杠/表示除法，用来进行整除运算；反斜杠\用来表示目录。
在 Unix 系统中，/表示目录；\表示跳脱字符将特殊字符变成一般字符
Windows由于使用斜杠/作为DOS命令提示符的参数标志了，为了不混淆，所以采用反斜杠\作为路径分隔符。所以目前windows系统上的文件浏览器都是用反斜杠\作为路径分隔符。</p>
</blockquote>
<h2 id="为什么重要">为什么重要？</h2>
<p>你是否曾经看过 Mac OS X 终端或文件系统，并注意到它与 Linux 的相似之处，以及它们与 Windows 的不同之处？嗯，这就是为什么——Mac OSX 和 Linux 都是类 Unix 操作系统。</p>
<p>了解这段历史有助于您了解什么是“类 Unix”操作系统，以及为什么这么多操作系统看起来彼此如此相似而 Windows 似乎如此不同。这解释了为什么 Linux 极客会觉得 Mac OS X 上的终端如此熟悉，而 Windows 上的命令提示符和 PowerShell 与其他命令行环境如此不同。</p>
<p>这只是一个简短的历史，它将帮助您了解我们如何到达今天的位置，而不会陷入细节中。如果您想了解更多信息，可以找到有关 Unix 历史的整本书。</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
