<?xml-stylesheet href="/rss.xsl" type="text/xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Chen&#39;s Life</title>
    <link>https://www.chens.life/</link>
    <description>Recent content on Chen&#39;s Life</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-cn</language>
    <copyright> flyto2035. 本站遵循 CC-BY-NC 4.0 协议</copyright>
    <lastBuildDate>Sun, 14 Jun 2026 14:53:07 +0800</lastBuildDate>
    
        <atom:link href="https://www.chens.life/index.xml" rel="self" type="application/rss+xml" />
    
    
    
    
        <item>
        <title>关于 AI 的一些思考</title>
        <link>https://www.chens.life/posts/my-thinking-about-ai/</link>
        <pubDate>Sat, 07 Mar 2026 16:55:23 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/my-thinking-about-ai/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/my-thinking-about-ai/ -&lt;p&gt;AI 时代，看来真的要来了。&lt;/p&gt;
&lt;p&gt;三年前，也就是 2023 年，当 OpenAI 的 ChatGPT 问世，全世界都在惊叹 LLM 的拟人性的时候，我只当它是一个聊天工具或者查询工具。那时候我以为 AI 能摧毁的是搜索引擎，而不是 Coding 或者 Math。&lt;/p&gt;
&lt;p&gt;三年后的今天，当各行各业都在使用 LLM 重新定义行业标准的时候，当全世界的大小团队都在推出自己的新模型和新技术或者新的理念的时候，我真正意识到未来可能真的要由 AI 来重新谱写了。&lt;/p&gt;
&lt;p&gt;未来也许不是 LLM 的，但一定是属于 AI 的。也许 LLM 已经到达了发展的阈值，但 AI 前进的步伐不会停止，下一个技术爆炸的那一刻也许不会太远。&lt;/p&gt;
&lt;p&gt;时代造就英雄，身处在这惊涛骇浪的中心，个人的学习和努力还剩下多少价值？&lt;/p&gt;
&lt;p&gt;这个时代已经不再需要重复的低端劳动力和思考力，需要的是 AI 短时间内不会拥有的东西。&lt;/p&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;&lt;strong&gt;品味&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个人的品味是独一无二的，就像一个人的审美那样五花八门。培养美的品味，更高级别的，富有创造力的品味，是 AI 无论如何在短时间内都不会拥有的东西。&lt;/p&gt;
&lt;p&gt;培养欣赏美的直觉和能力，是一个人保持领先的关键因素，尤其在如今的 AI 时代中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;逻辑&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LLM 不具备广泛意义上的逻辑能力。&lt;/p&gt;
&lt;p&gt;逻辑就像互相连接的齿轮，也许未来随着 AI 技术的发展，AI 也会具有逻辑的能力，但逻辑能让我们知道什么是合理的，符合发展规律和事实规律的东西。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;长期规格&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当前 LLM 的局限性在于 context，它就相当于 LLM 的大脑容量。如果一个人拥有对事件信息的强大的处理和规划能力，那么他必然是超过 AI 一大截的。&lt;/p&gt;
&lt;p&gt;这个一个技术平权，知识平权的时代。&lt;/p&gt;
&lt;p&gt;LLM 的发展，极大的抹平了知识差距的鸿沟，让即使没受过教育的人也可以访问人类几千年积累的知识库。&lt;/p&gt;
&lt;p&gt;这将更加凸显出那些极具品味，富有逻辑，并善于长期规划的人的价值所在，因为解决一个难题将不再是一个细节性问题，而是一个工程性问题。&lt;/p&gt;
&lt;p&gt;工程学，逻辑学，心理学，美术和音乐，将是未来教育的重中之重，&lt;/p&gt;
- https://www.chens.life/posts/my-thinking-about-ai/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>Rust 中两种 static 生命周期标注的区别</title>
        <link>https://www.chens.life/posts/rust/differents-with-two-static-time-cycle/</link>
        <pubDate>Sun, 01 Dec 2024 23:23:17 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/rust/differents-with-two-static-time-cycle/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/rust/differents-with-two-static-time-cycle/ -&lt;h2 id=&#34;rust-中的-static-生命周期标注&#34;&gt;Rust 中的 static 生命周期标注&lt;/h2&gt;
&lt;p&gt;Rust 中有的 static 生命周期意味着该类型的生命周期同整个程序的生命周期相同，意味着编译器会认为它一直是有效的。&lt;/p&gt;
&lt;p&gt;在 Rust 中，有两种使用 static 生命周期标注的方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一种是类型本身的生命周期为 static: &lt;code&gt;T: &#39;static&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;另一种是，该类型指向的数据的生命周期为 static: &lt;code&gt;T: &amp;amp;&#39;static&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;它们之间是有本质区别的。&lt;/p&gt;
&lt;h3 id=&#34;t-static&#34;&gt;T: &amp;lsquo;static&lt;/h3&gt;
&lt;p&gt;它表示规定 T 类型本身的生命周期是是 static 的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;use&lt;/span&gt; std::fmt::Display;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    static_bound(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;a static str&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#78787e&#34;&gt;// OK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;// &amp;#39;static 要求 T 类型的可以在 &amp;#39;static 生命周期内使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;static_bound&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt;T: &lt;span style=&#34;color:#f3f99d&#34;&gt;Display&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ff5c57&#34;&gt;&amp;#39;static&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&lt;/span&gt;(t: &lt;span style=&#34;color:#f3f99d&#34;&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  println!(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;, t);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是 OK 的，因为 static_bound 的参数要求生命周期必须为 static,而字符串字面值的生命周期正好符合。&lt;/p&gt;
&lt;p&gt;但是下面的写法是错误的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;use&lt;/span&gt; std::fmt::Display;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ff5c57&#34;&gt;let&lt;/span&gt; a_str &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;a string&amp;#34;&lt;/span&gt;.to_string();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// 通过引用传递，生命周期依赖于 a_str 的作用域
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// 然而 a_str 的作用域不是整个程序(static)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        static_bound(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;a_str); &lt;span style=&#34;color:#78787e&#34;&gt;// OK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;// &amp;#39;static 要求 T 类型的可以在 &amp;#39;static 生命周期内使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;static_bound&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt;T: &lt;span style=&#34;color:#f3f99d&#34;&gt;Display&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ff5c57&#34;&gt;&amp;#39;static&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&lt;/span&gt;(t: &lt;span style=&#34;color:#f3f99d&#34;&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  println!(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;, t);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;a_str&lt;/code&gt; 的生命周期不是 static，而 &lt;code&gt;static_bound&lt;/code&gt; 要求 T 类型的生命周期必须为 static，所以编译报错，提示 &lt;code&gt;a_str&lt;/code&gt; 存活的不够长。&lt;/p&gt;
&lt;h3 id=&#34;t-static-1&#34;&gt;T: &amp;lsquo;&amp;amp;static&lt;/h3&gt;
&lt;p&gt;我们将 &lt;code&gt;static_bound&lt;/code&gt; 的参数列表改一下 &lt;code&gt;(t: &amp;amp;T)&lt;/code&gt;，表示T的引用的内容的生命周期是 static,此时编译通过。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;use&lt;/span&gt; std::fmt::Display;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ff5c57&#34;&gt;let&lt;/span&gt; a_str &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;a string&amp;#34;&lt;/span&gt;.to_string();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// 通过引用传递，生命周期依赖于 a_str 的作用域
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// 然后 a_str 的作用域不是整个程序(static)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        static_bound(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;a_str); &lt;span style=&#34;color:#78787e&#34;&gt;// OK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;// &amp;#39;static 要求 T 类型的可以在 &amp;#39;static 生命周期内使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;fn&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;static_bound&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt;T: &lt;span style=&#34;color:#f3f99d&#34;&gt;Display&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ff5c57&#34;&gt;&amp;#39;static&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&lt;/span&gt;(t: &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#f3f99d&#34;&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  println!(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;, t);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;&amp;amp;&#39;static&lt;/code&gt; 不管类型本身的生命周期，它只在乎引用所指向的内存中的数据是否在整个程序运行中存在。&lt;/p&gt;
&lt;p&gt;那么 &lt;code&gt;&amp;amp;a_str&lt;/code&gt; 指向一个字符串字面值，它一定在整个程序运行中存在，所以编译通过，它不在乎引用本身的作用域。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;通过上述例子可以看到:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;T: &#39;static&lt;/code&gt; 在乎的是 T 类型本身的生命周期，也就是 T 类型本身的作用域;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;T: &amp;amp;&#39;static&lt;/code&gt; 在乎的是 T 类型指向的数据的作用域。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在一般代码实践中，应该避免使用 &lt;code&gt;T: &amp;amp;&#39;static&lt;/code&gt; ，因为这表明，即使 T 类型的作用域不是整个程序运行周期，编译器也会使其通过编译，就如第三个例子。&lt;/p&gt;
&lt;p&gt;然而在遇到难以解决的生命周期的问题的时候，可以适当使用 &lt;code&gt;T: &#39;static&lt;/code&gt; 使程序通过编译，使编译器理解我们的意思，不再阻拦我们。&lt;/p&gt;
- https://www.chens.life/posts/rust/differents-with-two-static-time-cycle/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>写在2024</title>
        <link>https://www.chens.life/posts/written-in-2024-11/</link>
        <pubDate>Sat, 02 Nov 2024 01:27:17 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/written-in-2024-11/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/written-in-2024-11/ -&lt;p&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;当一个人从小小的校园中出发，带着行李在城市、农田和山林中穿梭的时候，我意识到，属于我的青春岁月就要结束了。&lt;/p&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;
&lt;p&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;2025年就要来了，时间如白驹过隙，流逝的飞快。&lt;/p&gt;
&lt;p&gt;所有的失望和遗憾都将留在这里。&lt;/p&gt;
&lt;hr&gt;











  


&lt;figure align=&#34;Center&#34; role=&#34;group&#34; aria-describedby=&#34;caption-c3c4b84dbc75fb1a7f056c46b97da69c&#34;&gt;
  &lt;a href=&#34;https://www.chens.life/posts/written-in-2024-11/IMG_20230708_183712.png&#34; class=&#34;img-link&#34;&gt;
    &lt;img src=&#34;https://www.chens.life/posts/written-in-2024-11/IMG_20230708_183712_hu_def48ed46c83e86b.png&#34;&gt;
  &lt;/a&gt;
  &lt;figcaption id=&#34;caption-c3c4b84dbc75fb1a7f056c46b97da69c&#34;&gt;
    夕阳、海滩，赶海的人&lt;br/&gt;&lt;font size=&#39;2&#39;&gt;2023.7 · 福州&lt;/font&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
- https://www.chens.life/posts/written-in-2024-11/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>xv6-labs-2022 Lab6 Multithreading 答案与解析</title>
        <link>https://www.chens.life/posts/mit-xv6-lab6/</link>
        <pubDate>Sun, 07 Apr 2024 23:56:33 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/mit-xv6-lab6/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/mit-xv6-lab6/ -&lt;p&gt;本文不再像前文那样进行细致的翻译和讲解。&lt;/p&gt;
&lt;p&gt;开始前，应该切换到 &lt;code&gt;thread&lt;/code&gt; 分支，注意需要阅读 xv6-book 的 Chapter 7: Scheduling 章节。我建议先阅读，后面再来做lab，这样你会具有一个更加具体的概念。&lt;/p&gt;
&lt;h2 id=&#34;uthread-switching-between-threads&#34;&gt;Uthread: switching between threads&lt;/h2&gt;
&lt;p&gt;在这个练习中，你需要在用户级别的线程系统中设计一个上下文(context)切换机制。&lt;/p&gt;
&lt;p&gt;xv6 提供了两个文件 &lt;code&gt;user/uthread.c&lt;/code&gt; 和 &lt;code&gt;user/uthread_switch.S&lt;/code&gt;，首先阅读这两个文件，尤其是 &lt;code&gt;uthread.c&lt;/code&gt;，知道它是如何运行的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你的任务：想出一个方法创建thread，并且在线程切换的时候保存和恢复CPU上下文。&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;思路&#34;&gt;思路&lt;/h3&gt;
&lt;h4 id=&#34;0x1&#34;&gt;0x1&lt;/h4&gt;
&lt;p&gt;根据xv6-book，切换线程需要保存和恢复CPU上下文（也就是寄存器）的相关信息，所以在 struct thread 中，需要有CPU寄存器的相关信息，你手动添加它。我们不需要保存全部的寄存器，只需要保存 &lt;strong&gt;&lt;a href=&#34;https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf&#34;&gt;callee-save registers&lt;/a&gt;&lt;/strong&gt;，你可以在 &lt;code&gt;kernel/proc.h&lt;/code&gt; 中找到相关的内容，不过还是建议你阅读前面的超链接，你便你更好的了解。&lt;/p&gt;
&lt;p&gt;所以在 &lt;code&gt;user/uthread.c&lt;/code&gt; 中定义一个 struct context 来保存 callee-save registers 的信息。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;context&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 ra; &lt;span style=&#34;color:#78787e&#34;&gt;// return address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  uint64 sp; &lt;span style=&#34;color:#78787e&#34;&gt;// stack pointer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// callee-saved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  uint64 s0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s3;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s4;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s5;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s6;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s7;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s8;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s9;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s10;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 s11;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;thread&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt;       stack[STACK_SIZE]; &lt;span style=&#34;color:#78787e&#34;&gt;/* the thread&amp;#39;s stack */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt;        state;             &lt;span style=&#34;color:#78787e&#34;&gt;/* FREE, RUNNING, RUNNABLE */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;context&lt;/span&gt; context;       &lt;span style=&#34;color:#78787e&#34;&gt;// register context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;0x2&#34;&gt;0x2&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;user/uthread_switch.S&lt;/code&gt; 中，需要用asm编写保存和恢复寄存器的汇编代码，如果你做过前面的lab，或者认真读了xv6 book，那么这个函数 &lt;code&gt;thread_switch(uint64, uint64)&lt;/code&gt; 和 &lt;code&gt;kernel/swtch.S&lt;/code&gt; 中的&lt;code&gt;swtch&lt;/code&gt;函数不能说一模一样，简直是没什么区别。&lt;/p&gt;
&lt;h4 id=&#34;0x3&#34;&gt;0x3&lt;/h4&gt;
&lt;p&gt;在 &lt;code&gt;thread_schedule&lt;/code&gt; 中，很显然需要调用 &lt;code&gt;thread_swtich&lt;/code&gt; 函数来保存寄存器和恢复CPU上下文为即将运行的进程的上下文信息。&lt;/p&gt;
&lt;p&gt;xv6 book 中说道，thread switch 的原理就是通过保存原本的CPU上下文，然后恢复想要调度运行的进程的CPU上下文信息，其中最重要的就是寄存器 &lt;code&gt;ra&lt;/code&gt; 的值，因为它保存着函数将要返回的地址 return address. 所以此时 &lt;code&gt;ra&lt;/code&gt; 中的地址是什么，CPU就会跳转到这个地址进行运行。这就是所谓的 thread switch. 不过为了保持原本线程中的数据的完整性，需要一并恢复它所需要的寄存器的信息，也就是 callee-save resigers.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;thread_schedule&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (current_thread &lt;span style=&#34;color:#ff6ac1&#34;&gt;!=&lt;/span&gt; next_thread) {         &lt;span style=&#34;color:#78787e&#34;&gt;/* switch threads?  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;/* YOUR CODE HERE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;     * Invoke thread_switch to switch from t to next_thread:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;     * thread_switch(??, ??);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// switch old to new thread
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// save old thread context and restore new thread context
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    thread_switch(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;current_thread&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#ff6ac1&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    next_thread &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;thread_switch&lt;/code&gt; 函数的参数原型：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;extern&lt;/span&gt; &lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;thread_switch&lt;/span&gt;(&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;context&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;old, &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;context&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;new&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;0x4&#34;&gt;0x4&lt;/h4&gt;
&lt;p&gt;通过上述0x3的讲解，你应该清楚了线程切换的根本原理。如何在一开始 &lt;code&gt;thread_schedule&lt;/code&gt; 函数调度的时候，切换的新的CPU上下文信息中的 &lt;code&gt;ra&lt;/code&gt; 寄存器为我们想要调转的那个函数的地址呢？答案就是在 &lt;code&gt;thread_create&lt;/code&gt; 的时候，提前将对应的 thread 的 &lt;code&gt;ra&lt;/code&gt; 寄存器设置为对应的函数地址。&lt;/p&gt;
&lt;p&gt;同时需要注意，每个 thread 拥有一个独立的 stack 空间。所以需要同时将寄存器 &lt;code&gt;sp&lt;/code&gt; (stack pointer) 设置为 &lt;code&gt;thread.stack&lt;/code&gt; 的地址。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;thread_create&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;func)())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;thread&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;t;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;for&lt;/span&gt; (t &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; all_thread; t &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; all_thread &lt;span style=&#34;color:#ff6ac1&#34;&gt;+&lt;/span&gt; MAX_THREAD; t&lt;span style=&#34;color:#ff6ac1&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;state &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; FREE) &lt;span style=&#34;color:#ff6ac1&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;state &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; RUNNABLE;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// YOUR CODE HERE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// save stack pointer to stack address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context.sp &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (uint64)&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;stack[&lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context.ra &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (uint64)(&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;func);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;是不是挺有道理的？不过就是结果不正确，你会发现，经过一次两次 thread_switch 之后 &lt;code&gt;thread[0\1\2..]&lt;/code&gt; 中的某些数据被修改为一个随机值了。比如 &lt;code&gt;thread[0].state&lt;/code&gt; 在调度到 &lt;code&gt;thread_a&lt;/code&gt; 之后，莫名的被修改为了一个随机的值，它正确的值应该为 &lt;code&gt;1&lt;/code&gt;，因为它是 main 函数的线程，后面不会再进行调度。&lt;/p&gt;
&lt;p&gt;其实原因就是 &lt;code&gt;sp&lt;/code&gt; 的值错误了。学过操作系统原理的同学应该清楚，栈空间是从高往低填充的，也就是说 stack pointer 应该指向这个栈内存空间的高地址，而不是低地址。&lt;/p&gt;
&lt;p&gt;在 C 语言中，一个数组的空间是从低地址向高地址分配的，所以此时 &lt;code&gt;t-&amp;gt;stack&lt;/code&gt; 是这个数组的低地址，我们需要将它的高地址传给 &lt;code&gt;sp&lt;/code&gt; resiger. 也就是 &lt;code&gt;&amp;amp;t-&amp;gt;stack[STACK_SIZE-1];&lt;/code&gt;。
所以正确的应该是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// save stack pointer to stack address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context.sp &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (uint64)&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;stack[STACK_SIZE&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  t&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context.ra &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (uint64)(&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;func);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们应该掌握最基本的调式方法，详细的GDB调式方法见 &lt;a href=&#34;https://sourceware.org/gdb/current/onlinedocs/gdb.html/&#34;&gt;https://sourceware.org/gdb/current/onlinedocs/gdb.html/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;例如希望显示源代码 &lt;code&gt;layout src&lt;/code&gt; ，希望显示asm代码 &lt;code&gt;layout asm&lt;/code&gt;，二者都显示 &lt;code&gt;layout split&lt;/code&gt;，见 &lt;a href=&#34;https://sourceware.org/gdb/current/onlinedocs/gdb.html/TUI-Commands.html#TUI-Commands&#34;&gt;https://sourceware.org/gdb/current/onlinedocs/gdb.html/TUI-Commands.html#TUI-Commands&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在源代码中，如果执行 &lt;code&gt;next&lt;/code&gt; 会执行多行asm代码，如果向单行调试asm代码，需要执行 &lt;code&gt;si&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;详细的代码改动见 &lt;a href=&#34;https://github.com/relaxcn/xv6-labs-2022-solutions/commit/a965c2be0089a9fe8c827b2e873d76ade95a5008&#34;&gt;GitHub Commit&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;using-threads&#34;&gt;Using threads&lt;/h2&gt;
&lt;p&gt;详见 &lt;a href=&#34;https://github.com/relaxcn/xv6-labs-2022-solutions/commit/b95669c94e27e50427d105007d3ed1dae60b9e46&#34;&gt;GitHub commit&lt;/a&gt;，注意我的注释即可，最好画图分析一下指针，知道为什么会丢失数据。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;static&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;put&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; key, &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; value)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; key &lt;span style=&#34;color:#ff6ac1&#34;&gt;%&lt;/span&gt; NBUCKET;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// is the key already present?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;entry&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;e &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;for&lt;/span&gt; (e &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; table[i]; e &lt;span style=&#34;color:#ff6ac1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;; e &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; e&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;next) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (e&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;key &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; key)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(e){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// update the existing key.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    e&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;value &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#ff6ac1&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pthread_mutex_lock(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;lock[i]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// the new is new.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;//  重要的是 table[i] 的值，如果 thread_1 刚进入，但是 thread_2 刚好完成修改了 table[i] 的操作，此时就会丢失后面的所有node
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  insert(key, value, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;table[i], table[i]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pthread_mutex_unlock(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;lock[i]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;barrier&#34;&gt;Barrier&lt;/h2&gt;
&lt;p&gt;Barrier 是一种机制，可以让所有线程阻塞，直到所有线程都到达这个位置，然后继续运行。详见 &lt;a href=&#34;https://en.wikipedia.org/wiki/Barrier_(computer_science)&#34;&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pthread_cond_wait&lt;/code&gt; 在进入之后，会释放 mutex lock，返回之前会重新获取 mutex lock. 我们希望 &lt;code&gt;bstate.nthread&lt;/code&gt; 记录阻塞的线程的数量仅在一个 thread 中递增一次，而不是多次增加。在所有线程到达之后，重置 &lt;code&gt;bstate.nthread&lt;/code&gt; ，递增 &lt;code&gt;bstate.round&lt;/code&gt; 表示一次回合。&lt;/p&gt;
&lt;p&gt;首先我们需要使用 mutex lock 保护 &lt;code&gt;bstate.nthread&lt;/code&gt; 的递增。因为如何不保护它，那么在多线程中会导致其结果最后不正确。如果其本来是 0，此时刚好计算到 &lt;code&gt;bstate.nthread + 1&lt;/code&gt; 结束，结果是 1，但是还没有被赋值给 &lt;code&gt;bstate.nthread&lt;/code&gt;，但是此时另一个线程刚好在此之前完成了对 &lt;code&gt;bstate.nthread&lt;/code&gt; 的递增和赋值，此时 &lt;code&gt;bstate.nthread&lt;/code&gt; = 1，然后回到刚才线程，执行赋值操作 &lt;code&gt;bstate.nthread = 1&lt;/code&gt; 最终， &lt;code&gt;bstate.nthread&lt;/code&gt; 的值为 1，显然是错误的，应该是 2.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;barrier&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pthread_mutex_lock(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;bstate.barrier_mutex); &lt;span style=&#34;color:#78787e&#34;&gt;// Lock the mutex
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// Increment the number of threads that have reached this round
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  bstate.nthread&lt;span style=&#34;color:#ff6ac1&#34;&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// If not all threads have reached the barrier, wait
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (bstate.nthread &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; nthread) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      pthread_cond_wait(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;bstate.barrier_cond, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;bstate.barrier_mutex);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// If all threads have reached the barrier, increment the round and reset the counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (bstate.nthread &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; nthread) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      bstate.round&lt;span style=&#34;color:#ff6ac1&#34;&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      bstate.nthread &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      pthread_cond_broadcast(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;bstate.barrier_cond); &lt;span style=&#34;color:#78787e&#34;&gt;// Notify all waiting threads
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pthread_mutex_unlock(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;bstate.barrier_mutex); &lt;span style=&#34;color:#78787e&#34;&gt;// Unlock the mutex
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&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/relaxcn/xv6-labs-2022-solutions/commit/098ee563a1f34897b0667981277adf30a743fa21&#34;&gt;GitHub Commit&lt;/a&gt;.&lt;/p&gt;
- https://www.chens.life/posts/mit-xv6-lab6/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>xv6-labs-2022 Lab5 Copy on-write 答案与解析</title>
        <link>https://www.chens.life/posts/mit-xv6-lab5-cow/</link>
        <pubDate>Sat, 06 May 2023 16:53:28 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/mit-xv6-lab5-cow/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/mit-xv6-lab5-cow/ -&lt;p&gt;虚拟内存提供了一种间接性：内核可以将 PTE 标记为无效 (invalid) 或者只读 (read-only) 来阻止内存引用，并且导致页面故障 (page faults) 。在计算机系统中有一个说法，任何系统问题都能通过一定的间接性来解决。本次实验探索了一个例子：写时复制 (copy-on-write) fork.&lt;/p&gt;
&lt;p&gt;开始之前切换到 &lt;code&gt;cow&lt;/code&gt; 分支：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git fetch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git checkout cow
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make clean
&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;xv6 中的 &lt;code&gt;fork()&lt;/code&gt; 系统调用将父进程的所有用户空间内存都拷贝到子进程。如果父进程很大，那么这种拷贝将会花费很长时间。更糟糕的是，这经常会出现很大的浪费，因为 &lt;code&gt;fork()&lt;/code&gt; 在子进程中，通常后面跟着 &lt;code&gt;exec()&lt;/code&gt;，它通常使用已复制内存的很少一部分，这样就浪费了大量的内存空间。&lt;/p&gt;
&lt;h2 id=&#34;解决方法&#34;&gt;解决方法&lt;/h2&gt;
&lt;p&gt;你的任务是实现写时复制 (copy-on-write) fork()，它可以推迟实际的物理内存的分配，直到真正使用要使用的时候，才会复制物理内存页。&lt;/p&gt;
&lt;p&gt;COW fork() 仅仅为子进程创建了一个页表 (pagetable) ，页表中映射用户内存的 PTE 实际指向的是父进程的物理页。COW fork() 将父进程和子进程的用户 PTEs(user PTEs) 标记为只读 (read-only)。当任何一个进程试图向 COW 页写入操作的时候，CPU 将会引发一个页面错误 (page fault)。内核中的页面错误处理函数将会检测到这种情况，为发生错误的进程分配一个物理内存页，并把原始页（也就是父进程和子进程共享的物理页）中的数据复制到新分配的页中，然后修改故障进程中相关的 PTE ，使其指向新分配的物理页的地址，最后将此 PTE 标记为可写 (writeable)。 错误页面处理函数完成任务之后，用户进程对于它的复制页将是可写的。&lt;/p&gt;
&lt;p&gt;COW fork() 使得用户内存的物理页面的释放变得稍微有些复杂。一个给定的物理页有可能同时被多个进程所引用，这是因为由于 COW 的延迟分配机制，父进程和子进程共享同一个物理页所导致的。所以，我们应该在释放一个物理页的时候，确保该物理页没有一个进程在使用。在 xv6 这种简单内核中，我们的实现非常直接简单，仅仅使用一个数组来进行标记。但是在成熟内核中，这可能很难做到。&lt;/p&gt;
&lt;h2 id=&#34;implement-copy-on-write-forkhard&#34;&gt;Implement copy-on-write fork(&lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/labs/guidance.html&#34;&gt;hard&lt;/a&gt;)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;你的任务是在 xv6 内核中实现 copy-on-write fork 。如果运行 &lt;code&gt;cowtest&lt;/code&gt; 和 &lt;code&gt;usertests -q&lt;/code&gt; 都成功，那么这个实验就成功了。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;为了帮助你测试你的代码，我们提供了一个 &lt;code&gt;cowtest&lt;/code&gt; xv6 程序（源代码在 &lt;code&gt;user/cowtest.c&lt;/code&gt;。它将会运行多个测试，在没有修改的 xv6 中，它将会在第一个测试中就失败。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cowtest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;simple: fork&lt;span style=&#34;color:#ff6ac1&#34;&gt;()&lt;/span&gt; failed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个 &amp;ldquo;simple&amp;rdquo; 测试会分配超过一半的可用物理内存，然后调用 &lt;code&gt;fork()&lt;/code&gt; 。由于此时没有实现 COW fork() ，所以这里会因为没有足够的空闲内存空间而发生失败。&lt;/p&gt;
&lt;p&gt;当你完成的时候，运行这两个测试程序，应该显示如下结果：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cowtest
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;simple: ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;simple: ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;three: zombie!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;three: zombie!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;three: zombie!
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;file: ok
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ALL COW TESTS PASSED
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ usertests -q
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ALL TESTS PASSED
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;ol&gt;
&lt;li&gt;修改 &lt;code&gt;uvmcopy()&lt;/code&gt; ，将父进程的物理页映射到子进程，以避免分配新的页。同时清楚子进程和父进程 PTE 的 PTE_W 位，使它们标记为不可写。&lt;/li&gt;
&lt;li&gt;修改 &lt;code&gt;usertrap()&lt;/code&gt; ，以此来处理页面错误 (page fault)。当在一个本来可写的 COW 页发生“写页面错误” (write page-falut) 的时候，使用 &lt;code&gt;kalloc()&lt;/code&gt; 分配一个新的页，将旧页中的数据拷贝到新页中，并将新页的 PTE 的 PTE_W 位置为1. &lt;strong&gt;值得注意的是，对于哪些本来就使只读的（例如代码段），不论在旧页还是新页中，应该依旧保持它的只读性，那些试图对这样一个只读页进行写入的进程应该被杀死。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;确保没有一个物理页被 PTE 引用之后，再释放它们，不能提前释放。一个好的做法是，维持一个“引用计数数组” (reference count) ，使用索引代表对应的物理页，值代表被引用的个数。当调用 &lt;code&gt;kalloc()&lt;/code&gt; 分配一个物理页的时候，将其 &lt;code&gt;reference count&lt;/code&gt; 设置为 &lt;code&gt;1&lt;/code&gt; 。当 &lt;code&gt;fork&lt;/code&gt; 导致子进程共享同一个页的时候，递增其页的引用计数；当任何一个进程从它们的页表中舍弃这个页的时候，递减其页的引用计数。&lt;code&gt;kfree()&lt;/code&gt; 仅当一个页的引用计数为零时，才将这个页放到空闲页列表中。将这些引用计数放到一个 int 类型的数组中是可以的，你必须思考，如何去索引这个数组，以及如何选择这个数组的大小。例如，你可以用一个 &lt;code&gt;页的物理地址/4096&lt;/code&gt; 来索引数组。&lt;/li&gt;
&lt;li&gt;修改 &lt;code&gt;copyout()&lt;/code&gt; ，使用类似的思路去处理 COW 页。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一些注意的点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;记录一个 PTE 是否是 COW 映射是有帮助的。你可以使用 RISC-V PTE 的 RSW (reserved for software) 位来指示。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;usertests -q&lt;/code&gt; 测试一些 &lt;code&gt;cowtest&lt;/code&gt; 没有测试的东西，所以不要忘记两个测试都要通过。&lt;/li&gt;
&lt;li&gt;一些对于页表标志 (page table flags) 有用的宏和定义可以在 &lt;code&gt;kernel/riscv.h&lt;/code&gt; 中找到。&lt;/li&gt;
&lt;li&gt;如果一个 COW 页错误发生时，没有剩余可用内存，那么该进程应该被杀死。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;思路&#34;&gt;思路&lt;/h2&gt;
&lt;p&gt;首先需要处理引用计数的问题。在 &lt;code&gt;kernel/kalloc.c&lt;/code&gt; 中定义一个全局变量和锁。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;// the reference count of physical memory page
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; useReference[PHYSTOP&lt;span style=&#34;color:#ff6ac1&#34;&gt;/&lt;/span&gt;PGSIZE];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;spinlock&lt;/span&gt; ref_count_lock;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在函数 &lt;code&gt;kalloc()&lt;/code&gt; 中，初始化新分配的物理页的引用计数为 1.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;kalloc&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(r) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kmem.freelist &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; r&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;next;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    acquire(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;ref_count_lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// initialization the ref count to 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    useReference[(uint64)r &lt;span style=&#34;color:#ff6ac1&#34;&gt;/&lt;/span&gt; PGSIZE] &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    release(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;ref_count_lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  release(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;kmem.lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;kfree()&lt;/code&gt; ，仅当引用计数小于等于 0 的时候，才回收对应的页。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;kfree&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pa)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(((uint64)pa &lt;span style=&#34;color:#ff6ac1&#34;&gt;%&lt;/span&gt; PGSIZE) &lt;span style=&#34;color:#ff6ac1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;||&lt;/span&gt; (&lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)pa &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; end &lt;span style=&#34;color:#ff6ac1&#34;&gt;||&lt;/span&gt; (uint64)pa &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;=&lt;/span&gt; PHYSTOP)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    panic(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;kfree&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  acquire(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;ref_count_lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// decrease the reference count, if use reference is not zero, then return
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  useReference[(uint64)pa&lt;span style=&#34;color:#ff6ac1&#34;&gt;/&lt;/span&gt;PGSIZE] &lt;span style=&#34;color:#ff6ac1&#34;&gt;-=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  temp &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; useReference[(uint64)pa&lt;span style=&#34;color:#ff6ac1&#34;&gt;/&lt;/span&gt;PGSIZE];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  release(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;ref_count_lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (temp &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// Fill with junk to catch dangling refs.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;if (temp != 0)&lt;/code&gt; ，因为在系统运行开始的时候，需要对空闲页列表 (kmem.freelist) 进行初始化，此时的引用计数就为 &lt;code&gt;-1&lt;/code&gt; ，如果条件为 &lt;code&gt;temp != 0&lt;/code&gt; 那么这些空闲页就不能够回收，也就不能够 &lt;code&gt;kmem.freelist&lt;/code&gt; 列表了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fork&lt;/code&gt; 会首先调用 &lt;code&gt;uvmcopy()&lt;/code&gt; 给子进程分配内存空间。但是如果要实现 COW 机制，就需要在 fork 时不分配内存空间，而是让子进程和父进程同时共享父进程的内存页，并将其设置为只读，使用 PTE_RSW 位标记 COW 页。这样子进程没有使用到某些页的时候，系统就不会真正的分配物理内存。&lt;strong&gt;注意，此时需要将对应的引用计数加一。&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里在修改 PTE_W 和 PTE_RSW 位的时候，需要考虑原本的页是否使可写的。如果原本的页是只读的，那么就不用将其修改为 COW 页，因为 COW 页会在 &lt;code&gt;usertrap()&lt;/code&gt; 中重新分配内存，并赋予可写权限，这样就违背了其原来的意愿，导致安全问题。&lt;/p&gt;
&lt;p&gt;只有原本的页是可写的，才将其标记为 COW 和只读。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;首先在 &lt;code&gt;kernel/riscv.h&lt;/code&gt; 中增加一些定义。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;#define PTE_RSW (1L &amp;lt;&amp;lt; 8) &lt;/span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;// RSW
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后修改 &lt;code&gt;uvmcopy&lt;/code&gt; 函数。此函数在 &lt;code&gt;vm.c&lt;/code&gt; 文件中，由于需要使用 &lt;code&gt;useReference&lt;/code&gt; 引用计数，所以需要提前在文件开头声明。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#78787e&#34;&gt;&amp;#34;spinlock.h&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#78787e&#34;&gt;&amp;#34;proc.h&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;// Just declare the variables from kernel/kalloc.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;extern&lt;/span&gt; &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; useReference[PHYSTOP&lt;span style=&#34;color:#ff6ac1&#34;&gt;/&lt;/span&gt;PGSIZE];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;extern&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;spinlock&lt;/span&gt; ref_count_lock;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;uvmcopy&lt;/span&gt;(pagetable_t old, pagetable_t &lt;span style=&#34;color:#ff6ac1&#34;&gt;new&lt;/span&gt;, uint64 sz)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// char *mem;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;for&lt;/span&gt;(i &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; sz; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;+=&lt;/span&gt; PGSIZE){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;((pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; walk(old, i, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      panic(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;uvmcopy: pte should exist&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;((&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_V) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      panic(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;uvmcopy: page not present&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// PAY ATTENTION!!!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// 只有父进程内存页是可写的，才会将子进程和父进程都设置为COW和只读的；否则，都是只读的，但是不标记为COW，因为本来就是只读的，不会进行写入
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// 如果不这样做，父进程内存只读的时候，标记为COW，那么经过缺页中断，程序就可以写入数据，于原本的不符合
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_W) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#78787e&#34;&gt;// set PTE_W to 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;~&lt;/span&gt;PTE_W;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#78787e&#34;&gt;// set PTE_RSW to 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#78787e&#34;&gt;// set COW page
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;|=&lt;/span&gt; PTE_RSW;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pa &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; PTE2PA(&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// increment the ref count
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    acquire(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;ref_count_lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    useReference[pa&lt;span style=&#34;color:#ff6ac1&#34;&gt;/&lt;/span&gt;PGSIZE] &lt;span style=&#34;color:#ff6ac1&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    release(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;ref_count_lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    flags &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; PTE_FLAGS(&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// if((mem = kalloc()) == 0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;//   goto err;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// memmove(mem, (char*)pa, PGSIZE);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(mappages(&lt;span style=&#34;color:#ff6ac1&#34;&gt;new&lt;/span&gt;, i, PGSIZE, (uint64)pa, flags) &lt;span style=&#34;color:#ff6ac1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#78787e&#34;&gt;// kfree(mem);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;goto&lt;/span&gt; err;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一旦子进程真正需要某些页，由于页被设置为只读的，此时会触发 Store/AMO page fault，scause 寄存器的值为 15。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20230509135805346.png&#34; alt=&#34;image-20230509135805346&#34;&gt;&lt;/p&gt;
&lt;p&gt;在  &lt;code&gt;usertrap()&lt;/code&gt; 函数中捕获到 Store/AMO page fault 错误之后开始处理。首先应该知道哪个虚拟地址的操作导致了页错误。RISC-V 中的 stval (Supervisor Trap Value (stval) Register ) 寄存器中的值是导致发生异常的虚拟地址。vx6 中的函数 &lt;code&gt;r_stval()&lt;/code&gt; 可以获取该寄存器的值。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20230509140247324.png&#34; alt=&#34;image-20230509140247324&#34;&gt;&lt;/p&gt;
&lt;p&gt;修改 &lt;code&gt;usertrap&lt;/code&gt; 函数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;usertrap&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  syscall();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;if&lt;/span&gt; (r_scause() &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;15&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// Store/AMO page fault(write page fault)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// see Volume II: RISC-V Privileged Architectures V20211203 Page 71
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// the faulting virtual address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// see Volume II: RISC-V Privileged Architectures V20211203 Page 70
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// the download url is https://github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    uint64 va &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; r_stval();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (va &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;=&lt;/span&gt; p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;sz)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;killed &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; ret &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; cowhandler(p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;pagetable, va);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (ret &lt;span style=&#34;color:#ff6ac1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;killed &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#ff6ac1&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;if&lt;/span&gt;((which_dev &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; devintr()) &lt;span style=&#34;color:#ff6ac1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// ok
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  } &lt;span style=&#34;color:#ff6ac1&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;cowhandler&lt;/code&gt; 函数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;cowhandler&lt;/span&gt;(pagetable_t pagetable, uint64 va)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;mem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (va &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;=&lt;/span&gt; MAXVA)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pte_t &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; walk(pagetable, va, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// check the PTE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; ((&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_RSW) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;||&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_U) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;||&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_V) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; ((mem &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; kalloc()) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// old physical address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    uint64 pa &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; PTE2PA(&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// copy old data to new mem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    memmove((&lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)mem, (&lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)pa, PGSIZE);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// PAY ATTENTION
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// decrease the reference count of old memory page, because a new page has been allocated
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    kfree((&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)pa);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    uint flags &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; PTE_FLAGS(&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// set PTE_W to 1, change the address pointed to by PTE to new memory page(mem)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (PA2PTE(mem) &lt;span style=&#34;color:#ff6ac1&#34;&gt;|&lt;/span&gt; flags &lt;span style=&#34;color:#ff6ac1&#34;&gt;|&lt;/span&gt; PTE_W);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// set PTE_RSW to 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;~&lt;/span&gt;PTE_RSW;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;cowhandler&lt;/code&gt; 要进行严格的检查。只有被标记为 COW，存在，且是属于用户级别的，才可以被分配内存。如果本来的页就是只读的，那么在此时尝试对其进行写入，就会返回 -1，最终被杀死。&lt;/p&gt;
&lt;p&gt;接着修改 &lt;code&gt;kernel.vm.c&lt;/code&gt; 中的 &lt;code&gt;copyout()&lt;/code&gt; 函数。这里的思路和 &lt;code&gt;uvmcopy()&lt;/code&gt; 中类似。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;checkcowpage&lt;/span&gt;(uint64 va, pte_t &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte, &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;proc&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt; p) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; (va &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;sz) &lt;span style=&#34;color:#78787e&#34;&gt;// va should blow the size of process memory (bytes)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_V) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_RSW); &lt;span style=&#34;color:#78787e&#34;&gt;// pte is COW page
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;copyout&lt;/span&gt;(pagetable_t pagetable, uint64 dstva, &lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;src, uint64 len)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pa0 &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; walkaddr(pagetable, va0);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(pa0 &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;proc&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;p &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; myproc();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pte_t &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; walk(pagetable, va0, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;killed &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// check
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (checkcowpage(va0, pte, p)) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;mem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; ((mem &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; kalloc()) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// kill the process
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;killed &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&lt;span style=&#34;color:#ff6ac1&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        memmove(mem, (&lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)pa0, PGSIZE);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// PAY ATTENTION!!!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// This statement must be above the next statement
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        uint flags &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; PTE_FLAGS(&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// decrease the reference count of old memory that va0 point
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// and set pte to 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        uvmunmap(pagetable, va0, &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// change the physical memory address and set PTE_W to 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (PA2PTE(mem) &lt;span style=&#34;color:#ff6ac1&#34;&gt;|&lt;/span&gt; flags &lt;span style=&#34;color:#ff6ac1&#34;&gt;|&lt;/span&gt; PTE_W);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// set PTE_RSW to 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;~&lt;/span&gt;PTE_RSW;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// update pa0 to new physical memory address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        pa0 &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (uint64)mem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    n &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; PGSIZE &lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt; (dstva &lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt; va0);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(n &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&lt;/span&gt; len)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      n &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;checkcowpage&lt;/code&gt; 检测 PTE 的标志。&lt;code&gt;uvmunmap&lt;/code&gt; 函数将 PTE 置零，并 &lt;code&gt;kfree&lt;/code&gt;  PTE 引用的物理页，其实这里的 &lt;code&gt;kfree&lt;/code&gt; 就是将 PTE 引用的物理页的引用计数减一。因为 &lt;code&gt;copyout&lt;/code&gt; 分配的一个新的物理页，所以不需要共享之前的旧页了。&lt;/p&gt;
&lt;p&gt;由于 &lt;code&gt;uvmunmap&lt;/code&gt; 将 PTE 置零，所以 &lt;code&gt;uint flags = PTE_FLAGS(*pte);&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/relaxcn/xv6-labs-2022-solutions/commit/d79e00a630a3944c76cf92cffc0d43f31a4ad7ee&#34;&gt;GitHub Comment&lt;/a&gt;.&lt;/p&gt;
- https://www.chens.life/posts/mit-xv6-lab5-cow/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>vcpkg &#43; cmake &#43; vscode 配置教程</title>
        <link>https://www.chens.life/posts/vcpkg-cmake-vscode/</link>
        <pubDate>Fri, 27 Jan 2023 15:58:36 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/vcpkg-cmake-vscode/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/vcpkg-cmake-vscode/ -&lt;p&gt;本文是使用 &lt;code&gt;vcpkg&lt;/code&gt; 、&lt;code&gt;cmake&lt;/code&gt; 、&lt;code&gt;vscode&lt;/code&gt; 进行 C++ 开发的环境配置教程。&lt;/p&gt;
&lt;h2 id=&#34;环境描述&#34;&gt;环境描述&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Linux  Debin11 5.15.79.1-microsoft-standard-WSL2&lt;/li&gt;
&lt;li&gt;git version 2.30.2&lt;/li&gt;
&lt;li&gt;curl 7.74.0&lt;/li&gt;
&lt;li&gt;tar (GNU tar) 1.34&lt;/li&gt;
&lt;li&gt;cmake version 3.18.4&lt;/li&gt;
&lt;li&gt;vcpkg package management program version 2023-01-24&lt;/li&gt;
&lt;li&gt;gcc (Debian 10.2.1-6) 10.2.1 20210110&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;安装-vcpkg&#34;&gt;安装 vcpkg&lt;/h2&gt;
&lt;p&gt;首先安装上述环境工具：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install gcc g++ gdb git curl tar make cmake
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从 Github 仓库中克隆 &lt;code&gt;vcpkg&lt;/code&gt; 的文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/Microsoft/vcpkg.git
&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; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./vcpkg/bootstrap-vcpkg.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;注意：这一步将会从 Github 下载文件，使用魔法会更加方便，只需设置一下代理即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#ff5c57&#34;&gt;http_proxy&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt;ip:port
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#ff5c57&#34;&gt;https_proxy&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt;ip:port
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;成功之后，在 &lt;code&gt;vcpkg&lt;/code&gt; 文件夹内将会有一个二进制可执行文件 &lt;code&gt;vcpkg&lt;/code&gt;，此时即可使用 &lt;code&gt;vcpkg&lt;/code&gt; 。&lt;/p&gt;
&lt;h2 id=&#34;安装所需要的库&#34;&gt;安装所需要的库&lt;/h2&gt;
&lt;p&gt;使用命令 &lt;code&gt;search&lt;/code&gt; 和 &lt;code&gt;install&lt;/code&gt; 可以搜索和安装库。例如我将要安装 &lt;code&gt;oatpp&lt;/code&gt; Web 框架：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./vcpkg/vcpkg search oatpp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./vcpkg/vcpkg install oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;[&lt;/span&gt;*&lt;span style=&#34;color:#ff6ac1&#34;&gt;]&lt;/span&gt;:x64-linux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;x64-linux&lt;/code&gt; 代表安装目标的机器类型。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这一步会从 GitHub 中下载 oatpp 的源代码，所以需要魔法科技。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;成功之后会提醒 oatpp 提供了 CMake 目标。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20230127152746973.png&#34; alt=&#34;image-20230127152746973&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;配置-vscode&#34;&gt;配置 vscode&lt;/h2&gt;
&lt;p&gt;新建一个项目文件夹，使用 vscode 打开该文件夹。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir oatpp-test
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;cd&lt;/span&gt; oatpp-test
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;code .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装 vscode 插件：C/C++ Extension Pack、CMake ，之后重启 vscode。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ctrl + Shift + p&lt;/code&gt; 输入 &lt;code&gt;settings json&lt;/code&gt; 开发工作区设置（JSON）。填入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;#34;cmake.configureSettings&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;#34;CMAKE_TOOLCHAIN_FILE&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&amp;lt;path to vcpkg&amp;gt;/scripts/buildsystems/vcpkg.cmake&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;#34;VCPKG_TARGET_TRIPLET&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;x64-linux&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;注意：将 &lt;code&gt;&amp;lt;path to vspkg&amp;gt;&lt;/code&gt; 替换为你的 &lt;code&gt;vcpkg&lt;/code&gt; 路径！！！&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;创建 &lt;code&gt;CMakeLists.txt&lt;/code&gt; 文件，填入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;cmake_minimum_required&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;VERSION&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;3.18&lt;/span&gt;)&lt;span style=&#34;color:#ff5c57&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;project&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;oatpp-test&lt;/span&gt;)&lt;span style=&#34;color:#ff5c57&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;add_executable&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;oatpp-test&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;main.cpp&lt;/span&gt;)&lt;span style=&#34;color:#ff5c57&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;set&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;CMAKE_CXX_STANDARD&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;17&lt;/span&gt;)&lt;span style=&#34;color:#ff5c57&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;find_package&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;oatpp&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;CONFIG&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;REQUIRED&lt;/span&gt;)&lt;span style=&#34;color:#ff5c57&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;target_link_libraries&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;oatpp-test&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;PRIVATE&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;oatpp::oatpp&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;oatpp::oatpp-test&lt;/span&gt;)&lt;span style=&#34;color:#ff5c57&#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.cpp&lt;/code&gt; 文件，填入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#78787e&#34;&gt;&amp;#34;oatpp/network/Server.hpp&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#78787e&#34;&gt;&amp;#34;oatpp/network/tcp/server/ConnectionProvider.hpp&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#78787e&#34;&gt;&amp;#34;oatpp/web/server/HttpConnectionHandler.hpp&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#f3f99d&#34;&gt;HelloHandler&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;public&lt;/span&gt; oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;web&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;server&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;HttpRequestHandler {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  std&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;shared_ptr&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt;OutgoingResponse&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  handle(&lt;span style=&#34;color:#ff6ac1&#34;&gt;const&lt;/span&gt; std&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;shared_ptr&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt;IncomingRequest&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;request) &lt;span style=&#34;color:#ff6ac1&#34;&gt;override&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    OATPP_LOGI(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;HelloHandler&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;this is a request!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;auto&lt;/span&gt; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; request&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;getHeaders().get(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;User-Agent&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;c_str();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    OATPP_LOGI(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;HelloHandler&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;User-Agent : %s&amp;#34;&lt;/span&gt;, i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; ResponseFactory&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;createResponse(Status&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;CODE_200, &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;Hello World&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;run&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Create Router for HTTP requests routing */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;auto&lt;/span&gt; router &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;web&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;server&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;HttpRouter&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;createShared();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  router&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;route(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;/hello&amp;#34;&lt;/span&gt;, std&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;make_shared&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt;HelloHandler&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Create HTTP connection handler with router */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;auto&lt;/span&gt; connectionHandler &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;web&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;server&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;HttpConnectionHandler&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;createShared(router);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Create TCP connection provider */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;auto&lt;/span&gt; connectionProvider &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;network&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;tcp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;server&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;ConnectionProvider&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;createShared(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          {&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff9f43&#34;&gt;8000&lt;/span&gt;, oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;network&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;Address&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;IP_4});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Create server which takes provided TCP connections and passes them to HTTP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;   * connection handler */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;network&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;Server server(connectionProvider, connectionHandler);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Print info about server port */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  OATPP_LOGI(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;MyApp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;Server running on port %s&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             connectionProvider&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;getProperty(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;).getData());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Run server */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  server.run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Init oatpp Environment */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;base&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;Environment&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;init();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Run App */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;/* Destroy oatpp Environment */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  oatpp&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;base&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;Environment&lt;span style=&#34;color:#ff6ac1&#34;&gt;::&lt;/span&gt;destroy();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此代码参考 oatpp 官方文档：&lt;a href=&#34;https://oatpp.io/docs/start/step-by-step/#add-request-handler&#34;&gt;https://oatpp.io/docs/start/step-by-step/#add-request-handler&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ctrl + Shift + p&lt;/code&gt; 输入 &lt;code&gt;cmake configure&lt;/code&gt; ，选择 &lt;strong&gt;CMake：配置&lt;/strong&gt;。这将会配置该 CMake 工程项目。&lt;/p&gt;
&lt;p&gt;完成之后即可发现 &lt;code&gt;main.cpp&lt;/code&gt; 中的代码已经不报错了，在 vscode 底部状态栏也出现了 CMake 工具。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20230127155145068.png&#34; alt=&#34;image-20230127155145068&#34;&gt;&lt;/p&gt;
&lt;p&gt;点击 &lt;code&gt;Build&lt;/code&gt; 之后再点击最右边的运行箭头，即可编译运行该测试程序。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20230127155553208.png&#34; alt=&#34;image-20230127155553208&#34;&gt;&lt;/p&gt;
&lt;p&gt;访问 &lt;a href=&#34;http://localhost:8000/hello&#34;&gt;http://localhost:8000/hello&lt;/a&gt;，即可看到字符 &lt;code&gt;Hello World&lt;/code&gt;。终端中可以看到访问端的 &lt;code&gt;User-Agent&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20230127155513464.png&#34; alt=&#34;image-20230127155513464&#34;&gt;&lt;/p&gt;
- https://www.chens.life/posts/vcpkg-cmake-vscode/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>xv6-labs-2022 Lab4 traps 答案与解析</title>
        <link>https://www.chens.life/posts/mit-xv6-lab4/</link>
        <pubDate>Mon, 21 Nov 2022 18:32:42 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/mit-xv6-lab4/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/mit-xv6-lab4/ -&lt;p&gt;这个实验将会探索系统调用是如何使用陷阱（trap）实现的。首先将会利用栈做一个热身练习，接下来你将会实现一个用户级陷阱处理（user-level trap handling）的例子。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;阅读  &lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/xv6/book-riscv-rev3.pdf&#34;&gt;xv6 book&lt;/a&gt; 第四章节和以下相关文件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kernel/trampoline.S&lt;/code&gt; ：从用户空间到内核空间并返回的汇编代码。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kernel/trap.c&lt;/code&gt;：处理所有中断的代码。&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;开始之前，切换到 &lt;code&gt;trap&lt;/code&gt; 分支。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git fetch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git checkout traps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make clean
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;risc-v-assembly&#34;&gt;RISC-V assembly&lt;/h2&gt;
&lt;p&gt;理解 RISC-V 的汇编代码很重要。使用命令 &lt;code&gt;make fs.img&lt;/code&gt; 编译 &lt;code&gt;user/call.c&lt;/code&gt; ，这将会生成一个可读的汇编代码文件 &lt;code&gt;user/call.asm&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;阅读 &lt;code&gt;call.asm&lt;/code&gt; 中的 &lt;code&gt;g&lt;/code&gt; ，&lt;code&gt;f&lt;/code&gt; ，和 &lt;code&gt;main&lt;/code&gt; 函数。参考这些材料：&lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/reference.html&#34;&gt;reference page&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id=&#34;0x1&#34;&gt;0x1&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Which registers contain arguments to functions? For example, which register holds 13 in main&amp;rsquo;s call to &lt;code&gt;printf&lt;/code&gt;?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;通过之前的阅读可知，调用函数时的参数传递使用寄存器 &lt;code&gt;a1&lt;/code&gt;, &lt;code&gt;a2&lt;/code&gt; 等通用寄存器。&lt;/p&gt;
&lt;p&gt;阅读 &lt;code&gt;call.asm&lt;/code&gt; 文件的第 45 行。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221119182846614.png&#34; alt=&#34;image-20221119182846614&#34;&gt;&lt;/p&gt;
&lt;p&gt;通过阅读 &lt;code&gt;call.asm&lt;/code&gt; 文件中的 &lt;code&gt;main&lt;/code&gt; 函数可知，调用 &lt;code&gt;printf&lt;/code&gt; 函数时，&lt;code&gt;13&lt;/code&gt; 被寄存器 &lt;code&gt;a2&lt;/code&gt; 保存。&lt;/p&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;a1&lt;/code&gt;, &lt;code&gt;a2&lt;/code&gt;, &lt;code&gt;a3&lt;/code&gt; 等通用寄存器；&lt;code&gt;13&lt;/code&gt; 被寄存器 &lt;code&gt;a2&lt;/code&gt; 保存。&lt;/p&gt;
&lt;h3 id=&#34;0x2&#34;&gt;0x2&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Where is the call to function &lt;code&gt;f&lt;/code&gt; in the assembly code for main? Where is the call to &lt;code&gt;g&lt;/code&gt;? (Hint: the compiler may inline functions.)&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;通过阅读函数 &lt;code&gt;f&lt;/code&gt; 和 &lt;code&gt;g&lt;/code&gt; 得知：函数 &lt;code&gt;f&lt;/code&gt; 调用函数 &lt;code&gt;g&lt;/code&gt; ；函数 &lt;code&gt;g&lt;/code&gt; 使传入的参数加 3 后返回。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221119183441521.png&#34; alt=&#34;image-20221119183441521&#34;&gt;&lt;/p&gt;
&lt;p&gt;所以总结来说，函数 &lt;code&gt;f&lt;/code&gt; 就是使传入的参数加 3 后返回。考虑到编译器会进行内联优化，这就意味着一些显而易见的，编译时可以计算的数据会在编译时得出结果，而不是进行函数调用。&lt;/p&gt;
&lt;p&gt;查看 &lt;code&gt;main&lt;/code&gt; 函数可以发现，&lt;code&gt;printf&lt;/code&gt; 中包含了一个对 &lt;code&gt;f&lt;/code&gt; 的调用。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221119183826612.png&#34; alt=&#34;image-20221119183826612&#34;&gt;&lt;/p&gt;
&lt;p&gt;但是对应的会汇编代码却是直接将 &lt;code&gt;f(8)+1&lt;/code&gt; 替换为 &lt;code&gt;12&lt;/code&gt; 。这就说明编译器对这个函数调用进行了优化，所以对于 &lt;code&gt;main&lt;/code&gt; 函数的汇编代码来说，其并没有调用函数 &lt;code&gt;f&lt;/code&gt; 和 &lt;code&gt;g&lt;/code&gt; ，而是在运行之前由编译器对其进行了计算。&lt;/p&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main&lt;/code&gt; 的汇编代码没有调用 &lt;code&gt;f&lt;/code&gt; 和 &lt;code&gt;g&lt;/code&gt; 函数。编译器对其进行了优化。&lt;/p&gt;
&lt;h3 id=&#34;0x3&#34;&gt;0x3&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;At what address is the function &lt;code&gt;printf&lt;/code&gt; located?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;通过搜索容易得到 &lt;code&gt;printf&lt;/code&gt; 函数的位置。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221119184248121.png&#34; alt=&#34;image-20221119184248121&#34;&gt;&lt;/p&gt;
&lt;p&gt;得到其地址在 &lt;code&gt;0x642&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;0x642&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;0x4&#34;&gt;0x4&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;What value is in the register &lt;code&gt;ra&lt;/code&gt; just after the &lt;code&gt;jalr&lt;/code&gt; to &lt;code&gt;printf&lt;/code&gt; in &lt;code&gt;main&lt;/code&gt;?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;auipc&lt;/code&gt; 和 &lt;code&gt;jalr&lt;/code&gt; 的配合，可以跳转到任意 32 位的地址。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221119185052056.png&#34; alt=&#34;image-20221119185052056&#34;&gt;&lt;/p&gt;
&lt;p&gt;具体相关命令介绍请看参考链接：&lt;a href=&#34;https://xiayingp.gitbook.io/build_a_os/hardware-device-assembly/risc-v-assembly&#34;&gt;reference1&lt;/a&gt;, &lt;a href=&#34;https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf&#34;&gt;RISC-V unprivileged instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;第 49 行，使用 &lt;code&gt;auipc ra,0x0&lt;/code&gt; 将当前程序计数器 &lt;code&gt;pc&lt;/code&gt; 的值存入 &lt;code&gt;ra&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;第 50 行，&lt;code&gt;jalr 1554(ra)&lt;/code&gt; 跳转到偏移地址 &lt;code&gt;printf&lt;/code&gt; 处，也就是 &lt;code&gt;0x642&lt;/code&gt; 的位置。&lt;/p&gt;
&lt;p&gt;根据 &lt;a href=&#34;https://xiayingp.gitbook.io/build_a_os/hardware-device-assembly/risc-v-assembly&#34;&gt;reference1&lt;/a&gt; 中的信息，在执行完这句命令之后， 寄存器 &lt;code&gt;ra&lt;/code&gt; 的值设置为 &lt;code&gt;pc + 4&lt;/code&gt; ，也就是 &lt;code&gt;return address&lt;/code&gt; 返回地址 &lt;code&gt;0x38&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;jalr&lt;/code&gt; 指令执行完毕之后，&lt;code&gt;ra&lt;/code&gt; 的值为 &lt;code&gt;0x38&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;0x5&#34;&gt;0x5&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Run the following code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0x00646c72&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;H%x Wo%s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff9f43&#34;&gt;57616&lt;/span&gt;, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;i);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What is the output? &lt;a href=&#34;https://www.asciitable.com/&#34;&gt;Here&amp;rsquo;s an ASCII table&lt;/a&gt; that maps bytes to characters.&lt;/p&gt;
&lt;p&gt;The output depends on that fact that the RISC-V is little-endian. If the RISC-V were instead big-endian what would you set &lt;code&gt;i&lt;/code&gt; to in order to yield the same output? Would you need to change &lt;code&gt;57616&lt;/code&gt; to a different value?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.webopedia.com/TERM/b/big_endian.html&#34;&gt;Here&amp;rsquo;s a description of little- and big-endian&lt;/a&gt; and &lt;a href=&#34;https://www.rfc-editor.org/ien/ien137.txt&#34;&gt;a more whimsical description&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;请查看在线 C Compiler 的运行结果 &lt;a href=&#34;https://cpp.sh/?source=%2F%2F+Example+program%0A%23include+%3Cstdio.h%3E%0A%0Aint+main()%0A%7B%0A++unsigned+int+i+%3D+0x00646c72%3B%0Aprintf(%22x%3D%25d+y%3D%25d%22%2C+3)%3B%0Areturn+0%3B%0A%7D&#34;&gt;c++ sell&lt;/a&gt;，它打印出了 &lt;code&gt;He110 World&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;首先，&lt;code&gt;57616&lt;/code&gt; 转换为 16 进制为 &lt;code&gt;e110&lt;/code&gt;，所以格式化描述符 &lt;code&gt;%x&lt;/code&gt; 打印出了它的 16 进制值。&lt;/p&gt;
&lt;p&gt;其次，如果在小端（little-endian）处理器中，数据&lt;code&gt;0x00646c72&lt;/code&gt; 的&lt;strong&gt;高字节存储在内存的高位&lt;/strong&gt;，那么从&lt;strong&gt;内存低位&lt;/strong&gt;，也就是&lt;strong&gt;低字节&lt;/strong&gt;开始读取，对应的 ASCII 字符为 &lt;code&gt;rld&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果在 大端（big-endian）处理器中，数据 &lt;code&gt;0x00646c72&lt;/code&gt; 的&lt;strong&gt;高字节存储在内存的低位&lt;/strong&gt;，那么从&lt;strong&gt;内存低位&lt;/strong&gt;，也就是&lt;strong&gt;高字节&lt;/strong&gt;开始读取其 ASCII 码为 &lt;code&gt;dlr&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;所以如果大端序和小端序输出相同的内容 &lt;code&gt;i&lt;/code&gt; ，那么在其为大端序的时候，&lt;code&gt;i&lt;/code&gt; 的值应该为 &lt;code&gt;0x726c64&lt;/code&gt;，这样才能保证从内存低位读取时的输出为 &lt;code&gt;rld&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;无论  &lt;code&gt;57616&lt;/code&gt; 在大端序还是小端序，它的二进制值都为 &lt;code&gt;e110&lt;/code&gt; 。大端序和小端序只是改变了多字节数据在内存中的存放方式，并不改变其真正的值的大小，所以 &lt;code&gt;57616&lt;/code&gt; 始终打印为二进制 &lt;code&gt;e110&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;关于大小端，参考：&lt;a href=&#34;https://blog.csdn.net/wwwlyj123321/article/details/100066463&#34;&gt;CSDN&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;p&gt;如果在大端序，&lt;code&gt;i&lt;/code&gt; 的值应该为 &lt;code&gt;0x00646c72&lt;/code&gt; 才能保证与小端序输出的内容相同。不用该变 &lt;code&gt;57616&lt;/code&gt; 的值。&lt;/p&gt;
&lt;h3 id=&#34;0x6&#34;&gt;0x6&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;In the following code, what is going to be printed after &lt;code&gt;&#39;y=&#39;&lt;/code&gt;? (note: the answer is not a specific value.) Why does this happen?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;x=%d y=%d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff9f43&#34;&gt;3&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;a1&lt;/code&gt;, &lt;code&gt;a2&lt;/code&gt; 等来传递。如果 &lt;code&gt;prinf&lt;/code&gt; 少传递一个参数，那么其仍会从一个确定的寄存器中读取其想要的参数值，但是我们并没有给出这个确定的参数并将其存储在寄存器中，所以函数将从此寄存器中获取到一个随机的不确定的值作为其参数。故而此例中，&lt;code&gt;y=&lt;/code&gt;后面的值我们不能够确定，它是一个垃圾值。&lt;/p&gt;
&lt;p&gt;答案：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;y=&lt;/code&gt; 之后的值为一个不确定的垃圾值。&lt;/p&gt;
&lt;h2 id=&#34;backtrace&#34;&gt;Backtrace&lt;/h2&gt;
&lt;p&gt;打印出 &lt;code&gt;backtrace&lt;/code&gt;，这是一个在错误发生时存在于栈中的函数调用列表，有利于调试。寄存器 &lt;code&gt;s0&lt;/code&gt; 包含一个指向当前栈帧 &lt;code&gt;stack frame&lt;/code&gt; 的指针，我们的任务就是使用栈帧遍历整个栈，打印每一个栈帧中的返回地址 &lt;code&gt;return address&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;实现一个 &lt;code&gt;backtrace()&lt;/code&gt; 函数在 &lt;code&gt;kernel/printf.c&lt;/code&gt; 中，并且在 &lt;code&gt;sys_sleep&lt;/code&gt; 中调用它。之后运行 &lt;code&gt;bttest&lt;/code&gt;，它将会调用 &lt;code&gt;sys_sleep&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; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;backtrace:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x0000000080002cda
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x0000000080002bb6
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x0000000080002898
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意事项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;kernel/defs.h&lt;/code&gt; 中添加函数 &lt;code&gt;backtrace()&lt;/code&gt; 的函数声明，以便在 &lt;code&gt;sys_sleep&lt;/code&gt; 中调用 &lt;code&gt;backtrace&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GCC 编译器将当前正在执行的函数的帧指针（frame pointer）存储到寄存器 &lt;code&gt;s0&lt;/code&gt; 中。在 &lt;code&gt;kernel/riscv.h&lt;/code&gt; 中添加以下代码：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;static inline uint64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;r_fp&lt;span style=&#34;color:#ff6ac1&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 x;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  asm volatile&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;mv %0, s0&amp;#34;&lt;/span&gt; : &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; x;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#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;backtrace&lt;/code&gt; 中调用此函数，将会读取当前帧指针。&lt;code&gt;r_fp()&lt;/code&gt; 使用&lt;a href=&#34;https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html&#34;&gt;内联汇编&lt;/a&gt;读取 &lt;code&gt;s0&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://pdos.csail.mit.edu/6.1810/2022/lec/l-riscv.txt&#34;&gt;课堂笔记&lt;/a&gt;中有关于栈帧的布局图片。注意，返回地址在帧指针的 -8 偏移量处；前一个帧指针位于当前帧指针的固定偏移量 (-16) 处。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;遍历栈帧需要一个停止条件。有用的信息是：每个内核栈由一整个页（4k对其）组成，所有的栈帧都在同一个页上面。你可以使用&lt;code&gt;PGROUNDDOWN(fp)&lt;/code&gt; 来定位帧指针所在的页面，从而确定循环停止的条件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;PGROUNDDOWN(fp)&lt;/code&gt; 总是表示 &lt;code&gt;fp&lt;/code&gt; 所在的这一页的起始位置。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;所以要在 &lt;code&gt;printf&lt;/code&gt; 中添加该函数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;backtrace&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 fp_address &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;r_fp&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;while&lt;/span&gt;(fp_address &lt;span style=&#34;color:#ff6ac1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;PGROUNDDOWN&lt;/span&gt;(fp_address)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;%p&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;(uint64&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)(fp_address&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;8&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fp_address &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;(uint64&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)(fp_address &lt;span style=&#34;color:#ff6ac1&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;16&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;kernel/defs.h&lt;/code&gt; 中添加该函数声明：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;            &lt;span style=&#34;color:#57c7ff&#34;&gt;backtrace&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;kerne/riscv.h&lt;/code&gt; 中添加 &lt;code&gt;r_sp&lt;/code&gt;函数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;inline&lt;/span&gt; uint64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;r_sp&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 x;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;mv %0, sp&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt; (x) );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; x;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;kernel/sysproc.c&lt;/code&gt; 中的 &lt;code&gt;sys_sleep&lt;/code&gt; 函数中添加该函数调用：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;sys_sleep&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;backtrace&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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/relaxcn/xv6-labs-2022-solutions/commit/c636291e238bc849a6ac9638dfd2a8e922c4febe&#34;&gt;github commit&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;alarm&#34;&gt;Alarm&lt;/h2&gt;
&lt;p&gt;这个练习将会添加一个特性：当一个进程使用 cpu 时，每隔一个特定的时间就提醒进程。如果我们想要限制一个进程使用 cpu 的时间，那么这个练习将会有帮助。&lt;/p&gt;
&lt;p&gt;你应该添加一个新的系统调用  &lt;code&gt;sigalarm(interval, handler)&lt;/code&gt;。如果一个应用调用了 &lt;code&gt;sigalarm(n, fn)&lt;/code&gt;那么这个进程每消耗 &lt;code&gt;n&lt;/code&gt; 个 ticks，内核应该确保函数 &lt;code&gt;fn&lt;/code&gt; 被调用。当 &lt;code&gt;fn&lt;/code&gt; 返回的时候，内核应该恢复现场，确保该进程在它刚才离开的地方继续执行。一个 tick 在 xv6 中是一个相当随意的单位时间，它取决于硬件时钟产生中断的快慢。如果一个应用调用 &lt;code&gt;sigalarm(0, 0)&lt;/code&gt; ，内核应该停止产生周期性的警报调用。&lt;/p&gt;
&lt;p&gt;在代码库中有 &lt;code&gt;user/alarmtest.c&lt;/code&gt; 程序用于检测实验的真确性。将它添加到 Makefile 文件中以便编译它。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;alarmtest&lt;/code&gt; 在 &lt;code&gt;test0&lt;/code&gt; 中调用  &lt;code&gt;sigalarm(2, periodic)&lt;/code&gt; ，使内核每隔 2 个 ticks 就调用 &lt;code&gt;periodic&lt;/code&gt; 函数。&lt;/p&gt;
&lt;p&gt;通过修改内核，使得内核可以调转到位于用户空间的处理函数（alarm handler），它将打印出 &amp;ldquo;alarm!&amp;rdquo; 字符。&lt;/p&gt;
&lt;p&gt;回忆一下之前的内容以及 xv6 book 中的第四章节的内容。当使用 trap 方式陷入内核的时候，会首先执行 &lt;code&gt;kernel/trampoline.S&lt;/code&gt; 中的 &lt;code&gt;uservec&lt;/code&gt; ，保存寄存器中的值以便返回时恢复现场，包括 &lt;code&gt;sepc&lt;/code&gt; 中断时保存的用户程序的程序计数器（pc）；然后跳转到 &lt;code&gt;kernel/trap.c&lt;/code&gt; 中的 &lt;code&gt;usertrap(void)&lt;/code&gt; ，检测该中断的类型（是否是系统调用或者是 timer 时钟中断）；然后跳转到 &lt;code&gt;kernel/trap.c&lt;/code&gt; 中的 &lt;code&gt;usertrapret(void)&lt;/code&gt; ，它将从之前保存的栈帧(trapframe) 中恢复寄存器，其中一个重要的就是 &lt;code&gt;pec&lt;/code&gt; ，CPU 从 特权模式 返回 用户模式 ，将使用 &lt;code&gt;spec&lt;/code&gt; 的值恢复 &lt;code&gt;pc&lt;/code&gt; 的值，它决定了返回时，CPU 将要执行的用户代码。这一点很重要，我们的代码也是利用这一点，使 CPU 执行我们定义的用户空间中的 alarm handler 函数。&lt;/p&gt;
&lt;p&gt;需要注意的是，为了使得从 alarm handler 中返回之后，仍继续执行原用户程序，我们需要保存之前保存在 &lt;code&gt;trapframe&lt;/code&gt; 中的寄存器值，并且在 alarm handler 调用 &lt;code&gt;sys_sigreturn&lt;/code&gt; 时恢复这些寄存器。&lt;/p&gt;
&lt;p&gt;另外，为了保证实验说明中的要求：在 alarm handler 函数未返回之前，不能重复调用 alarm handler。我们需要一个控制这个状态的变量&lt;code&gt;have_return&lt;/code&gt;，它将会添加到 &lt;code&gt;struct proc&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;首先在 &lt;code&gt;kernel/proc.h&lt;/code&gt; 中的 &lt;code&gt;proc&lt;/code&gt; 结构体中添加需要的内容。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// the virtual address of alarm handler function in user page
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  uint64 handler_va;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; alarm_interval;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; passed_ticks;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// save registers so that we can re-store it when return to interrupted code.   
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; trapframe saved_trapframe;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// the bool value which show that is or not we have returned from alarm handler.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; have_return;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;kernel/sysproc.c&lt;/code&gt; 中实现 &lt;code&gt;sys_sigalarm&lt;/code&gt; 和 &lt;code&gt;sys_sigreturn&lt;/code&gt; 。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uint64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;sys_sigreturn&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt; proc &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;myproc&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// re-store trapframe so that it can return to the interrupt code before.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;trapframe &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;saved_trapframe;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;have_return &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#78787e&#34;&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;trapframe&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;a0;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uint64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;sys_sigalarm&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; ticks;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 handler_va;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;argint&lt;/span&gt;(&lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;ticks);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;argaddr&lt;/span&gt;(&lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;handler_va);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt; proc &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;myproc&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;alarm_interval &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; ticks;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;handler_va &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; handler_va;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;have_return &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#78787e&#34;&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;sys_sigreturn(void)&lt;/code&gt; 的返回值不是 0，而是 &lt;code&gt;proc-&amp;gt;trapframe-&amp;gt;a0&lt;/code&gt;。这是因为我们想要完整的恢复所有寄存器的值，包括 &lt;code&gt;a0&lt;/code&gt;。但是一个系统调用返回的时候，它会将其返回值存到 &lt;code&gt;a0&lt;/code&gt; 寄存器中，那这样就改变了之前 &lt;code&gt;a0&lt;/code&gt; 的值。所以，我们干脆让其返回之前想要恢复的 &lt;code&gt;a0&lt;/code&gt; 的值，那这样在其返回之后 &lt;code&gt;a0&lt;/code&gt; 的值仍没有改变。&lt;/p&gt;
&lt;p&gt;然后修改 &lt;code&gt;kernel/trap.c&lt;/code&gt; 中的 &lt;code&gt;usertrap&lt;/code&gt; 函数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;usertrap&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// give up the CPU if this is a timer interrupt.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(which_dev &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;2&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;proc &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;myproc&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// if proc-&amp;gt;alarm_interval is not zero
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// and alarm handler is returned.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;alarm_interval &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;have_return) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;++&lt;/span&gt;proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;passed_ticks &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;2&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;saved_trapframe &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;trapframe;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// it will make cpu jmp to the handler function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;trapframe&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;epc &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;handler_va;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// reset it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;passed_ticks &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#78787e&#34;&gt;// Prevent re-entrant calls to the handler
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;        proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;have_return &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;yield&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从内核跳转到用户空间中的 alarm handler 函数的关键一点就是：修改 &lt;code&gt;epc&lt;/code&gt; 的值，使 trap 在返回的时候将 pc 值修改为该 alarm handler 函数的地址。这样，我们就完成了从内核调转到用户空间中的 alarm handler 函数。但是同时，我们也需要保存之前寄存器栈帧，因为后来 alarm handler 调用系统调用 &lt;code&gt;sys_sigreturn&lt;/code&gt; 时会破坏之前保存的寄存器栈帧(p-&amp;gt;trapframe)。&lt;/p&gt;
&lt;p&gt;具体代码改动见：&lt;a href=&#34;https://github.com/relaxcn/xv6-labs-2022-solutions/commit/8dd68907b38ac6dbecfc93c4a452e6acb07313bd&#34;&gt;github commit&lt;/a&gt;.&lt;/p&gt;
- https://www.chens.life/posts/mit-xv6-lab4/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>如何将一个二进制值的指定位设置为指定的值</title>
        <link>https://www.chens.life/posts/how-to-set-a-specified-bit-of-a-binary-value-to-a-specified-value/</link>
        <pubDate>Mon, 07 Nov 2022 15:47:41 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/how-to-set-a-specified-bit-of-a-binary-value-to-a-specified-value/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/how-to-set-a-specified-bit-of-a-binary-value-to-a-specified-value/ -&lt;p&gt;如何将一串二进制的制定位设置为指定的值。假如有一串二进制值 &lt;code&gt;1010&lt;/code&gt; ，要将第二位设置为 &lt;code&gt;0&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;异或-&#34;&gt;异或 ^&lt;/h2&gt;
&lt;p&gt;首先需要了解异或 &lt;code&gt;^&lt;/code&gt; 运算符的概念和性质。和 0 异或等于它本身，相同的值异或等于 1。另外一个值得注意的是，一个数和同一个值异或两次等于它本身。&lt;/p&gt;
&lt;h2 id=&#34;公式&#34;&gt;公式&lt;/h2&gt;
&lt;p&gt;公式：&lt;code&gt;x = ((x&amp;amp;(1 &amp;lt;&amp;lt; n)) ^ x) ^ (a &amp;lt;&amp;lt; n)&lt;/code&gt;。 &lt;code&gt;x&lt;/code&gt; 为原值，&lt;code&gt;n&lt;/code&gt; 为第 &lt;code&gt;n&lt;/code&gt; 个值，&lt;code&gt;a&lt;/code&gt; 为想要设置的值（0或1）。&lt;/p&gt;
&lt;p&gt;首先 &lt;code&gt;(x&amp;amp;(1 &amp;lt;&amp;lt; n))&lt;/code&gt; 的值为：保留第 &lt;code&gt;n&lt;/code&gt; 位原来的值，其他位置零。再将此值与原值 &lt;code&gt;x&lt;/code&gt; 异或，得到一个值：除了第 &lt;code&gt;n&lt;/code&gt; 个值为零，其他位置为原值。（这是因为，与 &lt;code&gt;0&lt;/code&gt; 异或的那一位为原值，与相同值异或的那一位为 &lt;code&gt;0&lt;/code&gt;）。然后此时，再与 &lt;code&gt;(a &amp;lt;&amp;lt; n)&lt;/code&gt; 异或，将第 &lt;code&gt;n&lt;/code&gt; 位设置为 &lt;code&gt;a&lt;/code&gt; （这是因为与 &lt;code&gt;0&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; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1、原值：               &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; | &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; | &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;    x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2、其他位为0：          &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; | &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; | &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;    x &amp;amp; &lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;lt;&amp;lt; n )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;3、待设置的值           0 0 | 0 | 0    a &amp;lt;&amp;lt; n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4、将 &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; 和 &lt;span style=&#34;color:#ff9f43&#34;&gt;2&lt;/span&gt; 异或得到： &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; | &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; | &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;     x &amp;amp; &lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;lt;&amp;lt; n ) ^ x
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;5、将 3 和 4 异或得到： 1 0 | 0 | 0     ((x&amp;amp;(1 &amp;lt;&amp;lt; n&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;))&lt;/span&gt; ^ x&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; ^ &lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;a &amp;lt;&amp;lt; n&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;- https://www.chens.life/posts/how-to-set-a-specified-bit-of-a-binary-value-to-a-specified-value/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>xv6-labs-2022 Lab3 page tables 答案与解析</title>
        <link>https://www.chens.life/posts/mit-xv6-lab3/</link>
        <pubDate>Mon, 07 Nov 2022 15:22:44 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/mit-xv6-lab3/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/mit-xv6-lab3/ -&lt;p&gt;这个实验中，你将会探索页表，修改它们去加速一些系统调用，查看那些页被访问过。&lt;/p&gt;
&lt;p&gt;开始之前，需要将代码仓库切换到 &lt;code&gt;pgtbl&lt;/code&gt; 分支。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git fetch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git checkout pgtbl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make clean
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;speed-up-system-calls&#34;&gt;Speed up system calls&lt;/h2&gt;
&lt;p&gt;这个实验的原理就是，将一些数据存放到一个只读的共享空间中，这个空间位于内核和用户之间。这样用户程序就不用陷入内核中，而是直接从这个只读的空间中获取数据，省去了一些系统开销，加速了一些系统调用。这次的任务是改进 &lt;code&gt;getpid()&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;当每一个进程被创建，映射一个只读的页在 &lt;strong&gt;USYSCALL&lt;/strong&gt; （在&lt;code&gt;memlayout.h&lt;/code&gt;定义的一个虚拟地址）处。存储一个 &lt;code&gt;struct usyscall&lt;/code&gt; （定义在 &lt;code&gt;memlayout.h&lt;/code&gt;）结构体在该页的开始处，并且初始化这个结构体来保存当前进程的 PID。这个 lab 中，&lt;code&gt;ugetpid()&lt;/code&gt; 已经在用户空间给出，它将会使用 &lt;strong&gt;USYSCALL&lt;/strong&gt; 这个映射。运行 &lt;code&gt;pgtbltest&lt;/code&gt; ，如果正确，&lt;code&gt;ugetpid&lt;/code&gt; 这一项将会通过。（注意，这个程序包含两个测试，所以不用慌）。&lt;/p&gt;
&lt;p&gt;首先在 &lt;code&gt;kernel/proc.h&lt;/code&gt; proc 结构体中添加一项指针来保存这个共享页面的地址。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; usyscall &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;usyscallpage;  &lt;span style=&#34;color:#78787e&#34;&gt;// share page whithin kernel and user
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;kernel/proc.c&lt;/code&gt; 的 &lt;code&gt;allocproc()&lt;/code&gt; 中为其分配空间(&lt;code&gt;kalloc&lt;/code&gt;)。并初始化其保存当前进程的PID。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;allocproc&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; ((p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;usyscallpage &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; usyscall &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#57c7ff&#34;&gt;kalloc&lt;/span&gt;()) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;freeproc&lt;/span&gt;(p);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;release&lt;/span&gt;(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;lock);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;usyscallpage&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;pid &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;pid;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// Set up new context to start executing at forkret,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// which returns to user space.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;memset&lt;/span&gt;(&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ff6ac1&#34;&gt;sizeof&lt;/span&gt;(p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context.ra &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; (uint64)forkret;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;context.sp &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;kstack &lt;span style=&#34;color:#ff6ac1&#34;&gt;+&lt;/span&gt; PGSIZE;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;kernel/proc.c&lt;/code&gt; 的 &lt;code&gt;proc_pagetable(struct proc *p)&lt;/code&gt; 中将这个映射（PTE）写入 pagetable 中。权限是用户态可读。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;pagetable_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;proc_pagetable&lt;/span&gt;(&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;p) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#57c7ff&#34;&gt;mappages&lt;/span&gt;(pagetable, USYSCALL, PGSIZE, (uint64)(p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;usyscallpage), PTE_R &lt;span style=&#34;color:#ff6ac1&#34;&gt;|&lt;/span&gt; PTE_U) &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;uvmfree&lt;/span&gt;(pagetable, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// map the trampoline code (for system call return)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// at the highest user virtual address.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// only the supervisor uses it, on the way
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;kernel/proc.c&lt;/code&gt; 中的 &lt;code&gt;freeproc(struct proc *p)&lt;/code&gt; 。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;freeproc&lt;/span&gt;(&lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;p) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;trapframe)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;kfree&lt;/span&gt;((&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;trapframe);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;trapframe &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// add start
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;usyscallpage)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;kfree&lt;/span&gt;((&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;usyscallpage);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;usyscallpage &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#78787e&#34;&gt;// add end
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;(p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;pagetable)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;proc_freepagetable&lt;/span&gt;(p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;pagetable, p&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;sz);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#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;code&gt;panic&lt;/code&gt; 错误。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xv6 kernel is booting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hart &lt;span style=&#34;color:#ff9f43&#34;&gt;2&lt;/span&gt; starting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hart &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; starting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;panic: freewalk: leaf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是因为在 &lt;code&gt;pagetable&lt;/code&gt; 中任然存在我们之前的 PTE 映射。我们需要在 &lt;code&gt;kernel/proc.c&lt;/code&gt; 的 &lt;code&gt;proc_freepagetable(pagetable_t pagetable, uint64 sz)&lt;/code&gt; 中对其取消映射。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;proc_freepagetable&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;pagetable_t&lt;/span&gt; pagetable, uint64 sz) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;uvmunmap&lt;/span&gt;(pagetable, TRAMPOLINE, &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;uvmunmap&lt;/span&gt;(pagetable, TRAPFRAME, &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;uvmunmap&lt;/span&gt;(pagetable, USYSCALL, &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;); &lt;span style=&#34;color:#78787e&#34;&gt;// add
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;uvmfree&lt;/span&gt;(pagetable, sz);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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/relaxcn/xv6-labs-2022-solutions/commit/a4609f4237e864ce3c5085c8d4be4b3d00d637d8&#34;&gt;github commit&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：&lt;code&gt;proc_pagetable(struct proc *p)&lt;/code&gt; 中映射 PTE 时的权限应该为 &lt;code&gt;PTE_R | PTE_U&lt;/code&gt; 而不是 &lt;code&gt;PTE_R | PTE_U | PTE_W&lt;/code&gt;。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;运行 &lt;code&gt;./grade-lab-pgtbl ugetpid&lt;/code&gt; 即可得到成功信息。或者在 &lt;code&gt;qemu&lt;/code&gt; 中运行 &lt;code&gt;pgtbltest&lt;/code&gt; 。此时 &lt;code&gt;pgaccess_test&lt;/code&gt; 会失败，这个是下面的任务。&lt;/p&gt;
&lt;h2 id=&#34;print-a-page-table&#34;&gt;Print a page table&lt;/h2&gt;
&lt;p&gt;第二个任务是写一个函数来打印页表的内容。这个函数定义为 &lt;code&gt;vmprint()&lt;/code&gt; 。它应该接收一个 &lt;code&gt;pagetable_t&lt;/code&gt; 类型的参数，并且按照下面的格式打印。在 &lt;code&gt;exec.c&lt;/code&gt; 中的 &lt;code&gt;return argc&lt;/code&gt; 之前插入 &lt;code&gt;if(p-&amp;gt;pid==1) vmprint(p-&amp;gt;pagetable)&lt;/code&gt; ，用来打印第一个进程的页表。&lt;/p&gt;
&lt;p&gt;当你做完这些之后，运行 &lt;code&gt;qemu&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; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;page table 0x0000000087f6b000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ..0: pte 0x0000000021fd9c01 pa 0x0000000087f67000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. ..0: pte 0x0000000021fd9801 pa 0x0000000087f66000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. .. ..0: pte 0x0000000021fda01b pa 0x0000000087f68000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. .. ..1: pte 0x0000000021fd9417 pa 0x0000000087f65000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. .. ..2: pte 0x0000000021fd9007 pa 0x0000000087f64000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. .. ..3: pte 0x0000000021fd8c17 pa 0x0000000087f63000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ..255: pte 0x0000000021fda801 pa 0x0000000087f6a000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. ..511: pte 0x0000000021fda401 pa 0x0000000087f69000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. .. ..509: pte 0x0000000021fdcc13 pa 0x0000000087f73000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. .. ..510: pte 0x0000000021fdd007 pa 0x0000000087f74000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .. .. ..511: pte 0x0000000020001c0b pa 0x0000000080007000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;init: starting sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;可以将 &lt;code&gt;vmprint()&lt;/code&gt; 实现到 &lt;code&gt;kernel/vm.c&lt;/code&gt; 中。&lt;/li&gt;
&lt;li&gt;使用在 &lt;code&gt;kernel/riscv.h&lt;/code&gt; 文件末尾的宏定义。&lt;/li&gt;
&lt;li&gt;函数 &lt;code&gt;freewalk&lt;/code&gt; 的实现方法对本实验很有帮助。&lt;/li&gt;
&lt;li&gt;将函数 &lt;code&gt;vmprint&lt;/code&gt; 的声明放到 &lt;code&gt;kernel/defs.h&lt;/code&gt; 中，以便可以在 &lt;code&gt;exec.c&lt;/code&gt; 中调用它。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;%p&lt;/code&gt; 格式化打印64位十六进制的 PTEs 和 地址。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;值得注意的是 &lt;code&gt;freewalk&lt;/code&gt; 函数的具体实现。该函数会释放所有的页表（page-table pages），使用递归的形式访问到每一个子页面。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;1.png&#34; alt=&#34;1&#34;&gt;&lt;/p&gt;
&lt;p&gt;我们此次的 &lt;code&gt;vmprint&lt;/code&gt; 函数也可以效仿此递归方法，但是需要展示此页表的深度，这时我们可以另外设置一个静态变量来指示当前打印页的深度信息，如果需要进入下一级页表就将其加一，函数返回就减一。具体实现如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;vmprint&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;pagetable_t&lt;/span&gt; pagetable)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (printdeep &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;page table %p&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;, (uint64)pagetable);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;512&lt;/span&gt;; i&lt;span style=&#34;color:#ff6ac1&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#9aedfe&#34;&gt;pte_t&lt;/span&gt; pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; pagetable[i];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_V) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ff6ac1&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; j &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;; j &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;=&lt;/span&gt; printdeep; j&lt;span style=&#34;color:#ff6ac1&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#57c7ff&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;..&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#57c7ff&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;%d: pte %p pa %p&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;&lt;/span&gt;, i, (uint64)pte, (uint64)&lt;span style=&#34;color:#57c7ff&#34;&gt;PTE2PA&lt;/span&gt;(pte));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// pintes to lower-level page table
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt;((pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_V) &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; (PTE_R&lt;span style=&#34;color:#ff6ac1&#34;&gt;|&lt;/span&gt;PTE_W&lt;span style=&#34;color:#ff6ac1&#34;&gt;|&lt;/span&gt;PTE_X)) &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      printdeep&lt;span style=&#34;color:#ff6ac1&#34;&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      uint64 child_pa &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;PTE2PA&lt;/span&gt;(pte);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#57c7ff&#34;&gt;vmprint&lt;/span&gt;((&lt;span style=&#34;color:#9aedfe&#34;&gt;pagetable_t&lt;/span&gt;)child_pa);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      printdeep&lt;span style=&#34;color:#ff6ac1&#34;&gt;--&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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/relaxcn/xv6-labs-2022-solutions/commit/3343757349ffeff0c1d49a605bb4b6561a8d8ac5&#34;&gt;github commit&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;detect-which-pages-have-been-accessed&#34;&gt;Detect which pages have been accessed&lt;/h2&gt;
&lt;p&gt;首先需要了解的是，在一个 &lt;code&gt;Risc V Sv32&lt;/code&gt; page table 包含了 2^10 个 PTEs，每一个 4 bytes。&lt;code&gt;Sv32&lt;/code&gt; PTE 的图示如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;2.png&#34; alt=&#34;2&#34;&gt;&lt;/p&gt;
&lt;p&gt;参考 &lt;a href=&#34;https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-privileged-20190608.pdf&#34;&gt;RISC-V privileged architecture manual&lt;/a&gt; 的 P68 及以下几页。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each leaf PTE contains an accessed (A) and dirty (D) bit. The A bit indicates the virtual page has been read, written, or fetched from since the last time the A bit was cleared. The D bit indicates the virtual page has been written since the last time the D bit was cleared.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;（A）位代表此虚拟页被访问（读，写，获取）自上次（A）位被清理（置零）。&lt;/p&gt;
&lt;p&gt;这个实验中，我们将实现一个系统调用 &lt;code&gt;sys_pgaccess()&lt;/code&gt; 在文件 &lt;code&gt;kernel/sysproc.c&lt;/code&gt; 中。这个系统调用会告诉我们哪一个页被访问过。此系统调用接收三个参数。第一：被检查的第一个用户页的起始虚拟地址；第二：被检查页面的数量；第三：接收来自用户地址空间的一个 buffer 地址，将结果以掩码（bitmask）的形式写入。（掩码 bitmask 就是一个数据结构，其一个位代表一个页面，第一个页代表最低有效位）。&lt;/p&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在 &lt;code&gt;user/pgtlbtest.c&lt;/code&gt; 的 &lt;code&gt;pgacess_test()&lt;/code&gt; 展示了如何使用 &lt;code&gt;pgacess&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;argaddr()&lt;/code&gt; 和 &lt;code&gt;argint()&lt;/code&gt; 获取参数。&lt;/li&gt;
&lt;li&gt;对于要返回的 &lt;code&gt;bitmask&lt;/code&gt; 值，在 kernel 中建立临时的buffer，然后使用 &lt;code&gt;copyout&lt;/code&gt; 拷贝到用户空间（user space）。&lt;/li&gt;
&lt;li&gt;可以限制可以被扫描的页的最大数量（我的实现中没有设置）。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;kernel/vm.c&lt;/code&gt; 中的 &lt;code&gt;walk()&lt;/code&gt; 很有用。它可以找到一个虚拟地址对应的 PTE，返回其 physical address。&lt;/li&gt;
&lt;li&gt;需要在 &lt;code&gt;kernel/riscv.h&lt;/code&gt; 中定义一个 &lt;code&gt;PTE_A&lt;/code&gt;，其为 &lt;code&gt;Risc V&lt;/code&gt; 定义的 access bit。详细信息查看  &lt;a href=&#34;https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-privileged-20190608.pdf&#34;&gt;RISC-V privileged architecture manual&lt;/a&gt; 。&lt;/li&gt;
&lt;li&gt;检查完 &lt;code&gt;PTE_A&lt;/code&gt; 位时候设置之后，&lt;strong&gt;确保将其清零&lt;/strong&gt;。因为如果不清零，那么这些位都将会被设置为 1 。因为检查其是否设置这个过程就访问了此页面，在之后的过程中不能确定该页面（被检查之前）是否被访问过。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vmprint()&lt;/code&gt; 可能会在调试页表时很有用。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;walk()&lt;/code&gt; 函数的使用非常重要，它可以找到一个虚拟地址对应的 &lt;code&gt;PTE&lt;/code&gt; 的地址。而我们就是需要检查 PTE 来判断其是否被访问过（&lt;code&gt;PTE_A&lt;/code&gt; 是否被设置）。&lt;/p&gt;
&lt;p&gt;另一个重要的是要在检查之后清零此 &lt;code&gt;PTE_A&lt;/code&gt; 位，其在 &lt;code&gt;PTE&lt;/code&gt; 的第 6 位（从零开始）。如何将一个二进制值的指定位设置为指定的值呢？&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;2.png&#34; alt=&#34;2&#34;&gt;&lt;/p&gt;
&lt;p&gt;公式：&lt;code&gt;x = ((x&amp;amp;(1 &amp;lt;&amp;lt; n)) ^ x) ^ (a &amp;lt;&amp;lt; n)&lt;/code&gt;，详细解释见文章：&lt;a href=&#34;https://www.chens.life/posts/how-to-set-a-specified-bit-of-a-binary-value-to-a-specified-value/&#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; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#57c7ff&#34;&gt;sys_pgaccess&lt;/span&gt;(&lt;span style=&#34;color:#9aedfe&#34;&gt;void&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 va;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; pagenum;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 abitsaddr;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;argaddr&lt;/span&gt;(&lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;va);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;argint&lt;/span&gt;(&lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;pagenum);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#57c7ff&#34;&gt;argaddr&lt;/span&gt;(&lt;span style=&#34;color:#ff9f43&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;abitsaddr);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  uint64 maskbits &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;struct&lt;/span&gt; proc &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;proc &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;myproc&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#9aedfe&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;; i &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; pagenum; i&lt;span style=&#34;color:#ff6ac1&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#9aedfe&#34;&gt;pte_t&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#57c7ff&#34;&gt;walk&lt;/span&gt;(proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;pagetable, va&lt;span style=&#34;color:#ff6ac1&#34;&gt;+&lt;/span&gt;i&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;PGSIZE, &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#57c7ff&#34;&gt;panic&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;page not exist.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#57c7ff&#34;&gt;PTE_FLAGS&lt;/span&gt;(&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte) &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; PTE_A) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      maskbits &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; maskbits &lt;span style=&#34;color:#ff6ac1&#34;&gt;|&lt;/span&gt; (&lt;span style=&#34;color:#ff9f43&#34;&gt;1L&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#78787e&#34;&gt;// clear PTE_A, set PTE_A bits zero
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#78787e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; ((&lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;PTE_A) &lt;span style=&#34;color:#ff6ac1&#34;&gt;^&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;pte) &lt;span style=&#34;color:#ff6ac1&#34;&gt;^&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt; ;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#57c7ff&#34;&gt;copyout&lt;/span&gt;(proc&lt;span style=&#34;color:#ff6ac1&#34;&gt;-&amp;gt;&lt;/span&gt;pagetable, abitsaddr, (&lt;span style=&#34;color:#9aedfe&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt;maskbits, &lt;span style=&#34;color:#ff6ac1&#34;&gt;sizeof&lt;/span&gt;(maskbits)) &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#57c7ff&#34;&gt;panic&lt;/span&gt;(&lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;sys_pgacess copyout error&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff6ac1&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&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/relaxcn/xv6-labs-2022-solutions/commit/4489995876d00a8b4de22b7e06d93daef25d09e5&#34;&gt;github commit&lt;/a&gt;.&lt;/p&gt;
- https://www.chens.life/posts/mit-xv6-lab3/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
    
        <item>
        <title>xv6-labs-2022 Lab2 system call 答案与解析</title>
        <link>https://www.chens.life/posts/mit-xv6-lab2/</link>
        <pubDate>Wed, 02 Nov 2022 20:22:44 +0800</pubDate>
        
        <guid>https://www.chens.life/posts/mit-xv6-lab2/</guid>
        <description>Chen&#39;s Life https://www.chens.life/posts/mit-xv6-lab2/ -&lt;p&gt;本实验将会学习如何使用 GDB 进行调试，以及实现两个系统调用函数（System Call）。&lt;/p&gt;
&lt;p&gt;在开始之前，应该将 git 切换到 &lt;code&gt;syscall&lt;/code&gt; 分支。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;cd&lt;/span&gt; xv6-labs-2022
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git checkout syscall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make clean
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;using-gdb&#34;&gt;Using gdb&lt;/h2&gt;
&lt;p&gt;首先应该学习如何使用 GDB 进行调试本 xv6。查看&lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/labs/gdb.html&#34;&gt;此页面&lt;/a&gt;获得信息。&lt;/p&gt;
&lt;p&gt;需要注意的是，在 Ubuntu 20.04.5 LTS 中，需要安装并使用 &lt;code&gt;gdb-multiarch&lt;/code&gt;，只有这样才可以调试 &lt;code&gt;riscv64&lt;/code&gt;程序。&lt;/p&gt;
&lt;p&gt;进入 &lt;code&gt;xv6-labs-2022&lt;/code&gt;文件夹中。&lt;/p&gt;
&lt;p&gt;在终端中输入 &lt;code&gt;make qemu-gdb&lt;/code&gt; ，这将运行 qemu 并开启调试功能，在这里，端口为本地的 &lt;strong&gt;26000&lt;/strong&gt;。此时再打开一个终端，运行 &lt;code&gt;gdb-multiarch -x .gdbinit&lt;/code&gt;。这将运行 &lt;code&gt;.gdbinit&lt;/code&gt; 中的命令，也就是开启远程调试功能，并设置&lt;code&gt;arch&lt;/code&gt;架构为 &lt;code&gt;riscv64&lt;/code&gt;。具体可以查看此 &lt;code&gt;.gdbinit&lt;/code&gt;文件。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221029213304626.png&#34; alt=&#34;image-20221029213304626&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221029213635688.png&#34; alt=&#34;image-20221029213635688&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221029213443990.png&#34; alt=&#34;image-20221029213443990&#34;&gt;&lt;/p&gt;
&lt;p&gt;需要注意的是，如果 gdb 重新运行，那么 qemu 也应该重新运行。否则可能会出现意想不到的问题。&lt;/p&gt;
&lt;h3 id=&#34;0x1&#34;&gt;0x1&lt;/h3&gt;
&lt;p&gt;在 GDB 中运行以下指令。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; b syscall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Breakpoint &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; at 0x80001fe0: file kernel/syscall.c, line 133.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Continuing.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;[&lt;/span&gt;Switching to Thread 1.3&lt;span style=&#34;color:#ff6ac1&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Thread &lt;span style=&#34;color:#ff9f43&#34;&gt;3&lt;/span&gt; hit Breakpoint 1, syscall &lt;span style=&#34;color:#ff6ac1&#34;&gt;()&lt;/span&gt; at kernel/syscall.c:133
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;133&lt;/span&gt;     &lt;span style=&#34;color:#ff6ac1&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; layout src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; backtrace
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;b syscall&lt;/code&gt; 将在函数 &lt;code&gt;syscall&lt;/code&gt; 处设置断点； &lt;code&gt;c&lt;/code&gt; 将会运行到此断点时等待调试指令；&lt;code&gt;layout src&lt;/code&gt; 将会开启一个窗口展示调试时的源代码；&lt;code&gt;backtrace&lt;/code&gt; 将会打印堆栈回溯（stack backtrace)。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221029214535825.png&#34; alt=&#34;image-20221029214535825&#34;&gt;&lt;/p&gt;
&lt;p&gt;那么第一个问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Looking at the backtrace output, which function called &lt;code&gt;syscall&lt;/code&gt;?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;通过堆栈回溯可以看到，函数 &lt;code&gt;usertrap()&lt;/code&gt; 调用了 &lt;code&gt;syscall()&lt;/code&gt; 函数。&lt;/p&gt;
&lt;h3 id=&#34;0x2&#34;&gt;0x2&lt;/h3&gt;
&lt;p&gt;输入几个&lt;code&gt;n&lt;/code&gt; 命令，使其执行 &lt;code&gt;struct proc *p = myproc();&lt;/code&gt; 并打印 &lt;code&gt;*p&lt;/code&gt; 的值，它是一个 &lt;code&gt;proc&lt;/code&gt; 结构体。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; p/x *p
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;image-20221030190809519.png&#34; alt=&#34;image-20221030190809519&#34;&gt;&lt;/p&gt;
&lt;p&gt;那么第二个问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is the value of &lt;code&gt;p-&amp;gt;trapframe-&amp;gt;a7&lt;/code&gt; and what does that value represent? (Hint: look &lt;code&gt;user/initcode.S&lt;/code&gt;, the first user program xv6 starts.)&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;输入命令查看 &lt;code&gt;p-&amp;gt;trapframe-&amp;gt;a7&lt;/code&gt; 的值是多少。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; p p-&amp;gt;trapframe-&amp;gt;a7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;$2&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#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;a7&lt;/code&gt; 的值为 &lt;code&gt;7&lt;/code&gt; 。根据参考教材 &lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/xv6/book-riscv-rev1.pdf&#34;&gt;xv6 book&lt;/a&gt; 第二章和 &lt;code&gt;user/initcode.S&lt;/code&gt; 中的代码可知，这个 &lt;code&gt;a7&lt;/code&gt; 寄存器中保存了将要执行的系统调用号。这里的系统调用号为 &lt;code&gt;7&lt;/code&gt;，在 &lt;code&gt;kernel/syscall.h&lt;/code&gt; 中可以找到，这个系统调用为 &lt;code&gt;SYS_exec&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221030191403194.png&#34; alt=&#34;image-20221030191403194&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;0x3&#34;&gt;0x3&lt;/h3&gt;
&lt;p&gt;系统调用运行在内核模式（kernel mode)，可以通过 &lt;strong&gt;Supervisor Status Register (sstatus)&lt;/strong&gt; 来查看当前 CPU 的状态。具体参看官方  &lt;a href=&#34;https://github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf&#34;&gt;RISC-V privileged instructions&lt;/a&gt; 文档 4.1.1 章节。&lt;/p&gt;
&lt;p&gt;输入 GDB 命令来查看 &lt;code&gt;sstatus&lt;/code&gt; 寄存器。通过 &lt;code&gt;p/t&lt;/code&gt; 以二进制打印。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; p/t &lt;span style=&#34;color:#ff5c57&#34;&gt;$sstatus&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;$4&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;100010&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#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;sstatus&lt;/code&gt; 寄存器的图示。参考 &lt;a href=&#34;http://docs.keystone-enclave.org/en/latest/Getting-Started/How-Keystone-Works/RISC-V-Background.html#risc-v-privilieged-isa&#34;&gt;RISC-V Privilieged ISA&lt;/a&gt;。和以下解释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The SPP bit indicates the privilege level at which a hart was executing before entering supervisor mode. When a trap is taken, SPP is set to 0 if the trap originated from user mode, or 1 otherwise. When an SRET instruction (see Section 3.3.2) is executed to return from the trap handler, the privilege level is set to user mode if the SPP bit is 0, or supervisor mode if the SPP bit is 1; SPP is then set to 0.&lt;/p&gt;
&lt;p&gt;SPP 位指示进入管理员模式之前 hart 执行的特权级别。 当采取陷阱时，如果陷阱源自用户模式，则 SPP 设置为 0，否则设置为 1。 当执行 SRET 指令（见第 3.3.2 节）从陷阱处理程序返回时，如果 SPP 位为 0，则特权级别设置为用户模式，如果 SPP 位为 1，则设置为超级用户模式； 然后将 SPP 设置为 0。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;image-20221030192658267.png&#34; alt=&#34;image-20221030192658267&#34;&gt;&lt;/p&gt;
&lt;p&gt;根据 &lt;code&gt;sstatus&lt;/code&gt; 的二进制值 &lt;code&gt;100010&lt;/code&gt; 可知，SPP 位是 &lt;code&gt;0&lt;/code&gt;，那么在执行系统调用陷入内核之前的特权级别就是 user mode.&lt;/p&gt;
&lt;p&gt;所以问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What was the previous mode that the CPU was in?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;答案就是：用户模式（User Mode）。&lt;/p&gt;
&lt;h3 id=&#34;0x4&#34;&gt;0x4&lt;/h3&gt;
&lt;p&gt;在后续的实验中，我们编写的代码可能会使内核崩溃(panic)。例如替换 &lt;code&gt;syscall()&lt;/code&gt; 函数中的 &lt;code&gt;num = p-&amp;gt;trapframe-&amp;gt;a7;&lt;/code&gt; 为 &lt;code&gt;num = * (int *) 0;&lt;/code&gt;，然后运行 &lt;code&gt;make qemu&lt;/code&gt;。这样会看到一个 panic 信息。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：&lt;code&gt;syscall&lt;/code&gt; 函数位于 &lt;code&gt;kernel/syscall.c&lt;/code&gt; 132行。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;image-20221030200810283.png&#34; alt=&#34;image-20221030200810283&#34;&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xv6 kernel is booting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hart &lt;span style=&#34;color:#ff9f43&#34;&gt;2&lt;/span&gt; starting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hart &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; starting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scause 0x000000000000000d
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;sepc&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt;0x0000000080001ff4 &lt;span style=&#34;color:#ff5c57&#34;&gt;stval&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt;0x0000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;panic: kerneltrap
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的 &lt;code&gt;sepc&lt;/code&gt; 指代内核发生 panic 的代码地址。可以在 &lt;code&gt;kernel/kernel.asm&lt;/code&gt; 中查看编译后的完整内核汇编代码，在其中搜索这个地址既可以找到使内核 panic 的代码。&lt;code&gt;sepc&lt;/code&gt; 的值不是固定不变的。&lt;/p&gt;
&lt;p&gt;在这里是 &lt;code&gt;0x0000000080001ff4&lt;/code&gt;，所以我在 &lt;code&gt;kernel/kernel.asm&lt;/code&gt; 中搜索 &lt;code&gt;80001ff4&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221030201332014.png&#34; alt=&#34;image-20221030201332014&#34;&gt;&lt;/p&gt;
&lt;p&gt;可以看到，果然是 &lt;code&gt;num = * (int *) 0;&lt;/code&gt; 使内核 panic。对应的汇编则是 &lt;code&gt;lw a3,0(zero)&lt;/code&gt;。一些 risc v 的汇编指令的简单介绍看这里 &lt;a href=&#34;https://web.eecs.utk.edu/~smarz1/courses/ece356/notes/assembly/&#34;&gt;RISC-V Assembly Language&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221030201953431.png&#34; alt=&#34;image-20221030201953431&#34;&gt;&lt;/p&gt;
&lt;p&gt;所以这条汇编代码代表：将内存中地址从 0 开始的一个字 word （2 bytes) 大小的数据加载到寄存器 &lt;code&gt;a3&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;那么问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Write down the assembly instruction the kernel is panicing at. Which register corresponds to the varialable &lt;code&gt;num&lt;/code&gt;?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;答案就是：内核 panic 在 &lt;code&gt;lw a3,0(zero)&lt;/code&gt;。&lt;code&gt;num&lt;/code&gt; 代表 &lt;code&gt;a3&lt;/code&gt; 寄存器。&lt;/p&gt;
&lt;p&gt;0x5&lt;/p&gt;
&lt;p&gt;再次运行虚拟器和 GDB 调试。将断点设置在发生 panic 处。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; b *0x0000000080001ff4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Breakpoint &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; at 0x80001ff4: file kernel/syscall.c, line 138.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Continuing.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Thread &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; hit Breakpoint 1, syscall &lt;span style=&#34;color:#ff6ac1&#34;&gt;()&lt;/span&gt; at kernel/syscall.c:138
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; layout asm
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; Ctrl + C &lt;span style=&#34;color:#78787e&#34;&gt;# 键盘输入结束Thread&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; p &lt;span style=&#34;color:#ff5c57&#34;&gt;$scause&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;$1&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;13&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再次输入 &lt;code&gt;n&lt;/code&gt; 之后会发生 panic，此时输入 &lt;code&gt;Ctrl + C&lt;/code&gt; 结束。查看 &lt;code&gt;scase&lt;/code&gt; 寄存器，它代指内核 panic 的原因，查看文档&lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/labs/n//github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf&#34;&gt;RISC-V privileged instructions&lt;/a&gt; 4.1.8 章节。下面是 Exception Code 图标。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221030203515710.png&#34; alt=&#34;image-20221030203515710&#34;&gt;&lt;/p&gt;
&lt;p&gt;所以这里的 &lt;code&gt;13&lt;/code&gt; 代表 &lt;code&gt;Load page fault&lt;/code&gt; 。就是从内存地址 0 中 加载数据到寄存器 &lt;code&gt;a3&lt;/code&gt; 时出错。那么地址 0 处是什么数据呢？从本教材 &lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/xv6/book-riscv-rev3.pdf&#34;&gt;book-riscv-rev3.pdf&lt;/a&gt; 的 &lt;strong&gt;Figure 3.3&lt;/strong&gt; 中可以找到答案。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;image-20221030204838501.png&#34; alt=&#34;image-20221030204838501&#34;&gt;&lt;/p&gt;
&lt;p&gt;可以看到，在左侧 Virtual Address 中的地址 0 处对应右侧 Physical Address 的 Unused，表示这个地址没有被使用。而 Kernel 是从虚拟地址的 &lt;code&gt;0x80000000&lt;/code&gt; 处开始的。&lt;/p&gt;
&lt;p&gt;那么问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why does the kernel crash? Hint: look at figure 3-3 in the text; is address 0 mapped in the kernel address space? Is that confirmed by the value in &lt;code&gt;scause&lt;/code&gt; above? (See description of &lt;code&gt;scause&lt;/code&gt; in &lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/labs/n//github.com/riscv/riscv-isa-manual/releases/download/Priv-v1.12/riscv-privileged-20211203.pdf&#34;&gt;RISC-V privileged instructions&lt;/a&gt;)&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;答案：内核因为加载了一个未使用的地址 0 处的内存数据而崩溃（Load page fault）。地址 0 并不映射到内核空间中（从 &lt;code&gt;0x80000000&lt;/code&gt; 开始）。&lt;code&gt;scause&lt;/code&gt; 中的异常代码证实了上述观点。&lt;/p&gt;
&lt;h3 id=&#34;0x5&#34;&gt;0x5&lt;/h3&gt;
&lt;p&gt;上述 &lt;code&gt;scuase&lt;/code&gt; 指明了内核 panic 的原因。但是有时候我们需要知道，是哪一个用户程序调用 syscall 时发生了 panic。这可以通过打印 &lt;code&gt;proc&lt;/code&gt; 结构体中的 &lt;code&gt;name&lt;/code&gt; 来查看。&lt;/p&gt;
&lt;p&gt;重新启动 qemu 和 gdb。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; b syscall
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Breakpoint &lt;span style=&#34;color:#ff9f43&#34;&gt;1&lt;/span&gt; at 0x80001fe0: file kernel/syscall.c, line 133.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Continuing.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;[&lt;/span&gt;Switching to Thread 1.3&lt;span style=&#34;color:#ff6ac1&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Thread &lt;span style=&#34;color:#ff9f43&#34;&gt;3&lt;/span&gt; hit Breakpoint 1, syscall &lt;span style=&#34;color:#ff6ac1&#34;&gt;()&lt;/span&gt; at kernel/syscall.c:133
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff9f43&#34;&gt;133&lt;/span&gt;     &lt;span style=&#34;color:#ff6ac1&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; layout src
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; n
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; p p-&amp;gt;name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;$1&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;initcode\000\000\000\000\000\000\000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#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;initcode&lt;/code&gt; ，也是 xv6 第一个 process。&lt;/p&gt;
&lt;p&gt;打印 &lt;code&gt;proc&lt;/code&gt; 结构体可以查看这个进程的其他信息。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#34;&gt;)&lt;/span&gt; p *p
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;$3&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;lock&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ff5c57&#34;&gt;locked&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0, &lt;span style=&#34;color:#ff5c57&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0x80008178 &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;proc&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff5c57&#34;&gt;cpu&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0x0&lt;span style=&#34;color:#ff6ac1&#34;&gt;}&lt;/span&gt;, &lt;span style=&#34;color:#ff5c57&#34;&gt;state&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; RUNNING, &lt;span style=&#34;color:#ff5c57&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0x0, &lt;span style=&#34;color:#ff5c57&#34;&gt;killed&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0, &lt;span style=&#34;color:#ff5c57&#34;&gt;xstate&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff5c57&#34;&gt;pid&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 1, &lt;span style=&#34;color:#ff5c57&#34;&gt;parent&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0x0, &lt;span style=&#34;color:#ff5c57&#34;&gt;kstack&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 274877894656, &lt;span style=&#34;color:#ff5c57&#34;&gt;sz&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 4096, &lt;span style=&#34;color:#ff5c57&#34;&gt;pagetable&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0x87f73000, &lt;span style=&#34;color:#ff5c57&#34;&gt;trapframe&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0x87f74000, &lt;span style=&#34;color:#ff5c57&#34;&gt;context&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff5c57&#34;&gt;ra&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 2147488870, &lt;span style=&#34;color:#ff5c57&#34;&gt;sp&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 274877898368, &lt;span style=&#34;color:#ff5c57&#34;&gt;s0&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 274877898416, &lt;span style=&#34;color:#ff5c57&#34;&gt;s1&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 2147519792, &lt;span style=&#34;color:#ff5c57&#34;&gt;s2&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 2147518720, &lt;span style=&#34;color:#ff5c57&#34;&gt;s3&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 1, &lt;span style=&#34;color:#ff5c57&#34;&gt;s4&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0, &lt;span style=&#34;color:#ff5c57&#34;&gt;s5&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 3,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff5c57&#34;&gt;s6&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 2147588560, &lt;span style=&#34;color:#ff5c57&#34;&gt;s7&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 8, &lt;span style=&#34;color:#ff5c57&#34;&gt;s8&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 2147588856, &lt;span style=&#34;color:#ff5c57&#34;&gt;s9&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 4, &lt;span style=&#34;color:#ff5c57&#34;&gt;s10&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 1, &lt;span style=&#34;color:#ff5c57&#34;&gt;s11&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#ff6ac1&#34;&gt;}&lt;/span&gt;, &lt;span style=&#34;color:#ff5c57&#34;&gt;ofile&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;{&lt;/span&gt;0x0 &amp;lt;repeats &lt;span style=&#34;color:#ff9f43&#34;&gt;16&lt;/span&gt; times&amp;gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;}&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff5c57&#34;&gt;cwd&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; 0x80016e40 &amp;lt;itable+24&amp;gt;, &lt;span style=&#34;color:#ff5c57&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#ff6ac1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#5af78e&#34;&gt;&amp;#34;initcode\000\000\000\000\000\000\000&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#ff6ac1&#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;initcode&lt;/code&gt; 的 pid 为 1.&lt;/p&gt;
&lt;p&gt;问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is the name of the binary that was running when the kernel paniced? What is its process id (&lt;code&gt;pid&lt;/code&gt;)?&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;答案：这个二进制的名字为 &lt;code&gt;initcode&lt;/code&gt; ，其 process id 为 1.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：一些调试的方法可以看官网的PPT &lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2019/lec/gdb_slides.pdf&#34;&gt;Using the GNU Debugger&lt;/a&gt; 和 &lt;a href=&#34;https://pdos.csail.mit.edu/6.828/2022/labs/guidance.html&#34;&gt;guidance page&lt;/a&gt; 。&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2 id=&#34;system-call-tracing&#34;&gt;System call tracing&lt;/h2&gt;
&lt;p&gt;此任务会增加一个系统调用追踪功能，它将会在后续实验的调试时有所帮助。课程提供了一个 &lt;code&gt;trace&lt;/code&gt; 程序，它将会运行并开始另一个程序的系统调用追踪功能（tracing enable），此程序位于 &lt;code&gt;user/trace.c&lt;/code&gt;。其参数为一个掩码 mask ，用来指示其要追踪的系统调用。例如 &lt;code&gt;trace(1 &amp;lt;&amp;lt; SYS_fork)&lt;/code&gt;，&lt;code&gt;SYS_fork&lt;/code&gt; 为系统调用号在文件 &lt;code&gt;kernel/syscall.h&lt;/code&gt; 中。如果系统调用号被设置在掩码中，你必须修改 xv6 内核，当每一个追踪的系统调用将要返回的时候打印一行信息。这一行信息包含进程 id，系统调用的名字和要返回的值。你不需要打印系统调用的参数。&lt;code&gt;trace&lt;/code&gt; 系统调用应该启用它调用的程序和它调用程序的每一个子程序的追踪功能，但是不能影响其他进程。&lt;/p&gt;
&lt;p&gt;注意事项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将 &lt;code&gt;$U/_trace&lt;/code&gt; 添加到 Makefile 的 UPROGS 中。&lt;/li&gt;
&lt;li&gt;运行 &lt;code&gt;make qemu&lt;/code&gt; ，将会发现无法编译 &lt;code&gt;user/trace.c&lt;/code&gt;，这是因为编译器无法找到这个 &lt;code&gt;trace&lt;/code&gt; 系统调用的定义。在 &lt;code&gt;user/user.h&lt;/code&gt; 中添加这个系统调用的函数原型；在 &lt;code&gt;user/usys.pl&lt;/code&gt; 中添加一个 &lt;code&gt;entry&lt;/code&gt; ，它将会生成 &lt;code&gt;user/usys.S&lt;/code&gt; ，里面包含真实的汇编代码，它使用 Risc V 的 &lt;code&gt;ecall&lt;/code&gt; 指令陷入内核，执行系统调用；在 &lt;code&gt;kernel/syscal.h&lt;/code&gt; 中添加一个系统调用号。做完这些，&lt;code&gt;make qemu&lt;/code&gt; 就不会报错了。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;kernel/sysproc.c&lt;/code&gt; 中添加一个 &lt;code&gt;sys_trace()&lt;/code&gt; 函数作为系统调用。它通过将它的参数保存到 &lt;code&gt;proc&lt;/code&gt; 结构体（见 &lt;code&gt;kernel/proc.h&lt;/code&gt;）中的新变量中，来实现其功能。从用户空间获取系统调用参数的函数位于 &lt;code&gt;kernel/syscall.c&lt;/code&gt; 中，用法例子见 &lt;code&gt;kernel/sysproc.c&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;修改 &lt;code&gt;fork()&lt;/code&gt; （位于 &lt;code&gt;kernel/proc.c&lt;/code&gt;），从父程序拷贝追踪掩码（mask）到子进程。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;kernel/syscall.c&lt;/code&gt;修改 &lt;code&gt;syscall()&lt;/code&gt;，以此来打印系统调用 trace。你需要添加一个系统调用名字数组，用来索引。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个问题的关键在于，如何指定在 &lt;code&gt;syscall()&lt;/code&gt; 函数中只打印指定 syscall number 的信息。那么这个掩码 mask 就很重要。&lt;/p&gt;
&lt;p&gt;例如 &lt;code&gt;1 &amp;lt;&amp;lt; SYS_read&lt;/code&gt;，相当于 &lt;code&gt;1 &amp;lt;&amp;lt; 5&lt;/code&gt;，其二进制值为 &lt;code&gt;100000&lt;/code&gt;，那么这个二进制的第五位（如果从 0 开始算）为 1，就证明 系统调用号为 5 的需要被打印。&lt;/p&gt;
&lt;p&gt;又例如官网上的例子中 &lt;code&gt;trace trace 2147483647&lt;/code&gt; 这里 &lt;code&gt;2147483647&lt;/code&gt;就是二进制的 &lt;code&gt;01111111111111111111111111111111&lt;/code&gt;，其低31为全部为 1 ，就证明 30号（包括30号）以下的系统调用都需要跟踪）。&lt;/p&gt;
&lt;p&gt;可以使用一个 mask 来判断已知的系统调用是否需要跟踪打印。如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#e2e4e5;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff6ac1&#34;&gt;if&lt;/span&gt; ( (mask &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; num) &lt;span style=&#34;color:#ff6ac1&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#ff9f43&#34;&gt;0&lt;/span&gt;b1 )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    output
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也就是判断那一位是否为 1 ，来判断其是否需要打印。&lt;/p&gt;
&lt;h3 id=&#34;答案&#34;&gt;答案&lt;/h3&gt;
&lt;p&gt;文件变动见 &lt;a href=&#34;https://github.com/relaxcn/xv6-labs-2022-solutions/commit/b18aa26959504c9634cf1a9c67753a048911cdd7&#34;&gt;commit lab2 trace&lt;/a&gt;，共修改了 8 个文件。&lt;/p&gt;
&lt;p&gt;可通过运行 &lt;code&gt;./grade-lab-syscall trace&lt;/code&gt;  进行测试。&lt;/p&gt;
&lt;h2 id=&#34;sysinfo&#34;&gt;Sysinfo&lt;/h2&gt;
&lt;p&gt;这个部分将会实现一个系统调用 &lt;code&gt;sysinfo&lt;/code&gt;，它将收集正在运行的系统（xv6）的信息。此 system call 需要一个参数：一个指向 &lt;code&gt;struct sysinfo&lt;/code&gt; 的指针（见 &lt;code&gt;kernel/sysinfo.h&lt;/code&gt;）。在陷入内核后，内核将会填充这个结构体中的字段：&lt;code&gt;freemem&lt;/code&gt; 使系统剩余内存（free  memory）的数量（单位 bytes），&lt;code&gt;nproc&lt;/code&gt; 将会被设置为进程状态 &lt;code&gt;state&lt;/code&gt; 不是 &lt;code&gt;UNSED&lt;/code&gt; 的进程数量。我们提供了一个测试程序 &lt;code&gt;sysinfotest&lt;/code&gt;，如果它打印 &amp;ldquo;sysinfotest: OK&amp;rdquo; ，那么就通过了测试。&lt;/p&gt;
&lt;p&gt;注意事项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;具体一般信息看官方的 hints。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sysinfo&lt;/code&gt; 有一个参数来自于用户空间 &lt;code&gt;use space&lt;/code&gt; ，所以需要将内核空间（kernel space）中的数据（&lt;code&gt;struct sysinfo&lt;/code&gt;）填充（复制）到用户空间中的结构体中。这个需要用到 &lt;code&gt;copyout&lt;/code&gt;，具体例子请看 &lt;code&gt;sys_fstat()&lt;/code&gt;(&lt;code&gt;kernel/sysfile.c&lt;/code&gt;) 和 &lt;code&gt;filestat()&lt;/code&gt;(&lt;code&gt;kernel/file.c&lt;/code&gt;)。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;kernel/kalloc.c&lt;/code&gt; 中添加一个函数用于计算未使用的空闲内存。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;kernel/proc.c&lt;/code&gt; 中添加一个函数用于收集进程数量。&lt;/li&gt;
&lt;li&gt;这些函数的实现，可以参考其他官方的函数，会有一些启发。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;答案-1&#34;&gt;答案&lt;/h3&gt;
&lt;p&gt;文件改动见 &lt;a href=&#34;https://github.com/relaxcn/xv6-labs-2022-solutions/commit/ed66024c7020638bf201d0e11599c246a4db5f4f&#34;&gt;commit lab2 sysinfo&lt;/a&gt;，共修改了 9 个文件。&lt;/p&gt;
&lt;p&gt;可通过运行 `./grade-lab-syscall sysinfo  进行测试。&lt;/p&gt;
- https://www.chens.life/posts/mit-xv6-lab2/ -  flyto2035. 本站遵循 CC-BY-NC 4.0 协议</description>
        </item>
    
    
  </channel>
</rss> 