<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>RISC-V on 夜云泊</title>
    <link>https://lifeislife.cn/tags/risc-v/</link>
    <description>feedId:57980998056508425+userId:73222296380546048 Recent content in RISC-V on 夜云泊</description>
    <generator>Hugo -- 0.161.1</generator>
    <language>zh</language>
    <lastBuildDate>Thu, 15 Aug 2024 15:42:13 +0800</lastBuildDate>
    <atom:link href="https://lifeislife.cn/tags/risc-v/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>SCP-firmware 源码分析-module 间 api 调用分析</title>
      <link>https://lifeislife.cn/posts/scp-firmware%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-module%E9%97%B4api%E8%B0%83%E7%94%A8%E5%88%86%E6%9E%90/</link>
      <pubDate>Thu, 15 Aug 2024 15:42:13 +0800</pubDate>
      <guid>https://lifeislife.cn/posts/scp-firmware%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-module%E9%97%B4api%E8%B0%83%E7%94%A8%E5%88%86%E6%9E%90/</guid>
      <description>&lt;p&gt;想了解如何提供 API，我们先看看 CMN 模块是如何使用 API 的，在文件&lt;code&gt;module/cmn700/src/mod_cmn700.c&lt;/code&gt;我们可以看到如下代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// module/cmn700/src/mod_cmn700.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod_system_info_get_info_api&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_info_api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;cmn700_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system_info_api&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get_system_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;chip_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system_info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chip_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;multi_chip_mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system_info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;multi_chip_mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;他调用了&lt;code&gt;system_info_api-&amp;gt;get_system_info&lt;/code&gt;这个函数，实际这就是 mod_system_info 暴露给 mod_cmn700 的一个 API。用于获取系统信息。&lt;/p&gt;
&lt;p&gt;为何这个静态变量&lt;code&gt;system_info_api&lt;/code&gt;就能调用到&lt;code&gt;mod_system_info&lt;/code&gt;的函数呢？我们继续搜索代码，可以看到如下代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// module/cmn700/src/mod_cmn700.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;cmn700_bind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;round&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;fwk_id_is_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_ID_TYPE_MODULE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* Bind to system info module to obtain multi-chip info */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fwk_module_bind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;FWK_ID_MODULE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_SYSTEM_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;FWK_ID_API&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_SYSTEM_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MOD_SYSTEM_INFO_GET_API_IDX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_info_api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;cmn700_bind&lt;/code&gt;函数中，调用了&lt;code&gt;fwk_module_bind&lt;/code&gt;函数，这个函数的作用是绑定一个模块的 API，这样就可以通过这个 API 调用模块的函数。&lt;code&gt;fwk_module_bind&lt;/code&gt;函数的第一个参数是提供 API 的模块的 ID，比如当前是模块&lt;code&gt;system_info&lt;/code&gt;的 ID，如果是要用 USB 的 API，那么就是 USB 模块的 ID。第二个参数是 API 的 ID，这个 ID 是在模块的头文件中定义的，比如&lt;code&gt;mod_system_info.h&lt;/code&gt;中定义了&lt;code&gt;MOD_SYSTEM_INFO_GET_API_IDX&lt;/code&gt;，这个宏定义的值就是 API 的 ID。第三个参数是 API 的指针，这个指针就是开头提到的静态变量的地址，它是定义在使用 API 的模块中的。这样就可以通过 API 的指针调用模块的函数。对于 USB 模块，我们就需要在使用到 USB 的模块中定义一个静态变量。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fwk_module_bind&lt;/code&gt;做了什么呢？进入该函数，可以看到它回调了&lt;code&gt;mod_system_info&lt;/code&gt;的&lt;code&gt;process_bind_request&lt;/code&gt;函数，也就是&lt;code&gt;system_info_process_bind_request&lt;/code&gt;函数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// framework/src/fwk_module.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fwk_module_bind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;target_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;api_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_mod_ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;desc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;process_bind_request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;fwk_module_ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bind_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;target_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;api_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;system_info_process_bind_request&lt;/code&gt;函数的作用是根据 API 的 ID 返回 API 的指针。它把&lt;code&gt;get_system_info_api&lt;/code&gt;的地址赋值给了&lt;code&gt;api&lt;/code&gt;。这就实现了 API 的暴露。经过这个函数，&lt;code&gt;system_info_api&lt;/code&gt;就指向了&lt;code&gt;get_system_info_api&lt;/code&gt;。实际就是我们在&lt;code&gt;cmn700_bind&lt;/code&gt;函数中使用&lt;code&gt;system_info_api&lt;/code&gt;就是在调用&lt;code&gt;get_system_info_api&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// module/system_info/src/mod_system_info.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;system_info_process_bind_request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;requester_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targer_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;api_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;fwk_id_get_api_idx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;api_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;MOD_SYSTEM_INFO_GET_API_IDX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;api&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_system_info_api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_E_PARAM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解释完这个 bind 函数，它是在哪被调用的？它在框架初始化时就会被调用，分析&lt;code&gt;fwk_arch_init&lt;/code&gt;函数，可以看到在&lt;code&gt;fwk_module_start&lt;/code&gt;函数中会对每一个模块调用&lt;code&gt;bind&lt;/code&gt;函数。函数调用流程参考图片文件。在此就不再赘述了。&lt;/p&gt;
&lt;p&gt;经过以上分析，提供 API 的模块需要做的事情就是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在模块的头文件中定义 API 的 ID，它有一定的格式，具体可以参考 MSCP 文档&lt;code&gt;doc/framework.md&lt;/code&gt;的&lt;code&gt;APIs&lt;/code&gt;章节。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod_modulename_api&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MOD_MODULENAME_API_A&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;MOD_MODULENAME_API_B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在模块的源文件中定义 API 结构体，用于在其他模块中使用。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod_system_info_get_info_api&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_system_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod_system_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在模块原文件中提供&lt;code&gt;process_bind_request&lt;/code&gt;函数，用于根据 API 的 ID 返回 API 的指针。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;system_info_process_bind_request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;requester_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;targer_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;api_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;fwk_id_get_api_idx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;api_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;MOD_SYSTEM_INFO_GET_API_IDX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;api&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_system_info_api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_E_PARAM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在模块的源文件中定义 API 的指针，用于提供 API 的地址。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod_system_info_get_info_api&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get_system_info_api&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get_system_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system_info_get_system_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实现需要提供的 API 函数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;system_info_get_system_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod_system_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sys_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_SUCCESS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以上就是大致的移植流程了。&lt;/p&gt;
&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>想了解如何提供 API，我们先看看 CMN 模块是如何使用 API 的，在文件<code>module/cmn700/src/mod_cmn700.c</code>我们可以看到如下代码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// module/cmn700/src/mod_cmn700.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">struct</span> <span class="n">mod_system_info_get_info_api</span> <span class="o">*</span><span class="n">system_info_api</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">cmn700_start</span><span class="p">(</span><span class="kt">fwk_id_t</span> <span class="n">id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl">    <span class="n">status</span> <span class="o">=</span> <span class="n">system_info_api</span><span class="o">-&gt;</span><span class="nf">get_system_info</span><span class="p">(</span><span class="o">&amp;</span><span class="n">system_info</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">status</span> <span class="o">==</span> <span class="n">FWK_SUCCESS</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">chip_id</span> <span class="o">=</span> <span class="n">system_info</span><span class="o">-&gt;</span><span class="n">chip_id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">multi_chip_mode</span> <span class="o">=</span> <span class="n">system_info</span><span class="o">-&gt;</span><span class="n">multi_chip_mode</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>他调用了<code>system_info_api-&gt;get_system_info</code>这个函数，实际这就是 mod_system_info 暴露给 mod_cmn700 的一个 API。用于获取系统信息。</p>
<p>为何这个静态变量<code>system_info_api</code>就能调用到<code>mod_system_info</code>的函数呢？我们继续搜索代码，可以看到如下代码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// module/cmn700/src/mod_cmn700.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">cmn700_bind</span><span class="p">(</span><span class="kt">fwk_id_t</span> <span class="n">id</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">round</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nf">fwk_id_is_type</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">FWK_ID_TYPE_MODULE</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/* Bind to system info module to obtain multi-chip info */</span>
</span></span><span class="line"><span class="cl">        <span class="n">status</span> <span class="o">=</span> <span class="nf">fwk_module_bind</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nf">FWK_ID_MODULE</span><span class="p">(</span><span class="n">FWK_MODULE_IDX_SYSTEM_INFO</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="nf">FWK_ID_API</span><span class="p">(</span><span class="n">FWK_MODULE_IDX_SYSTEM_INFO</span><span class="p">,</span> <span class="n">MOD_SYSTEM_INFO_GET_API_IDX</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="o">&amp;</span><span class="n">system_info_api</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">status</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在<code>cmn700_bind</code>函数中，调用了<code>fwk_module_bind</code>函数，这个函数的作用是绑定一个模块的 API，这样就可以通过这个 API 调用模块的函数。<code>fwk_module_bind</code>函数的第一个参数是提供 API 的模块的 ID，比如当前是模块<code>system_info</code>的 ID，如果是要用 USB 的 API，那么就是 USB 模块的 ID。第二个参数是 API 的 ID，这个 ID 是在模块的头文件中定义的，比如<code>mod_system_info.h</code>中定义了<code>MOD_SYSTEM_INFO_GET_API_IDX</code>，这个宏定义的值就是 API 的 ID。第三个参数是 API 的指针，这个指针就是开头提到的静态变量的地址，它是定义在使用 API 的模块中的。这样就可以通过 API 的指针调用模块的函数。对于 USB 模块，我们就需要在使用到 USB 的模块中定义一个静态变量。</p>
<p><code>fwk_module_bind</code>做了什么呢？进入该函数，可以看到它回调了<code>mod_system_info</code>的<code>process_bind_request</code>函数，也就是<code>system_info_process_bind_request</code>函数。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// framework/src/fwk_module.c
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">fwk_module_bind</span><span class="p">(</span><span class="kt">fwk_id_t</span> <span class="n">target_id</span><span class="p">,</span> <span class="kt">fwk_id_t</span> <span class="n">api_id</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">*</span><span class="n">api</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl">    <span class="n">status</span> <span class="o">=</span> <span class="n">fwk_mod_ctx</span><span class="o">-&gt;</span><span class="n">desc</span><span class="o">-&gt;</span><span class="nf">process_bind_request</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">fwk_module_ctx</span><span class="p">.</span><span class="n">bind_id</span><span class="p">,</span> <span class="n">target_id</span><span class="p">,</span> <span class="n">api_id</span><span class="p">,</span> <span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="o">**</span><span class="p">)</span><span class="n">api</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>system_info_process_bind_request</code>函数的作用是根据 API 的 ID 返回 API 的指针。它把<code>get_system_info_api</code>的地址赋值给了<code>api</code>。这就实现了 API 的暴露。经过这个函数，<code>system_info_api</code>就指向了<code>get_system_info_api</code>。实际就是我们在<code>cmn700_bind</code>函数中使用<code>system_info_api</code>就是在调用<code>get_system_info_api</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// module/system_info/src/mod_system_info.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">system_info_process_bind_request</span><span class="p">(</span><span class="kt">fwk_id_t</span> <span class="n">requester_id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="kt">fwk_id_t</span> <span class="n">targer_id</span><span class="p">,</span> <span class="kt">fwk_id_t</span> <span class="n">api_id</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">**</span><span class="n">api</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">switch</span> <span class="p">(</span><span class="nf">fwk_id_get_api_idx</span><span class="p">(</span><span class="n">api_id</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">MOD_SYSTEM_INFO_GET_API_IDX</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="o">*</span><span class="n">api</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">get_system_info_api</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">FWK_E_PARAM</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">FWK_SUCCESS</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>解释完这个 bind 函数，它是在哪被调用的？它在框架初始化时就会被调用，分析<code>fwk_arch_init</code>函数，可以看到在<code>fwk_module_start</code>函数中会对每一个模块调用<code>bind</code>函数。函数调用流程参考图片文件。在此就不再赘述了。</p>
<p>经过以上分析，提供 API 的模块需要做的事情就是：</p>
<ol>
<li>
<p>在模块的头文件中定义 API 的 ID，它有一定的格式，具体可以参考 MSCP 文档<code>doc/framework.md</code>的<code>APIs</code>章节。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">enum</span> <span class="n">mod_modulename_api</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">MOD_MODULENAME_API_A</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">MOD_MODULENAME_API_B</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
<li>
<p>在模块的源文件中定义 API 结构体，用于在其他模块中使用。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">mod_system_info_get_info_api</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">get_system_info</span><span class="p">)(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">mod_system_info</span> <span class="o">**</span><span class="n">sys_info</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
<li>
<p>在模块原文件中提供<code>process_bind_request</code>函数，用于根据 API 的 ID 返回 API 的指针。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">system_info_process_bind_request</span><span class="p">(</span><span class="kt">fwk_id_t</span> <span class="n">requester_id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="kt">fwk_id_t</span> <span class="n">targer_id</span><span class="p">,</span> <span class="kt">fwk_id_t</span> <span class="n">api_id</span><span class="p">,</span> <span class="k">const</span> <span class="kt">void</span> <span class="o">**</span><span class="n">api</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">switch</span> <span class="p">(</span><span class="nf">fwk_id_get_api_idx</span><span class="p">(</span><span class="n">api_id</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">MOD_SYSTEM_INFO_GET_API_IDX</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="o">*</span><span class="n">api</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">get_system_info_api</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">FWK_E_PARAM</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">FWK_SUCCESS</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
<li>
<p>在模块的源文件中定义 API 的指针，用于提供 API 的地址。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="k">struct</span> <span class="n">mod_system_info_get_info_api</span> <span class="n">get_system_info_api</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">get_system_info</span> <span class="o">=</span> <span class="n">system_info_get_system_info</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div></li>
<li>
<p>实现需要提供的 API 函数。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">system_info_get_system_info</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">mod_system_info</span> <span class="o">**</span><span class="n">sys_info</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">*</span><span class="n">sys_info</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">system_info</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">FWK_SUCCESS</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div></li>
</ol>
<p>以上就是大致的移植流程了。</p>
<p>

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>SCP-firmware 源码分析 - 源码编译以及模块初始化流程</title>
      <link>https://lifeislife.cn/posts/scp-firmware%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E4%BB%A5%E5%8F%8A%E6%A8%A1%E5%9D%97%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B/</link>
      <pubDate>Sat, 10 Aug 2024 15:42:13 +0800</pubDate>
      <guid>https://lifeislife.cn/posts/scp-firmware%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E4%BB%A5%E5%8F%8A%E6%A8%A1%E5%9D%97%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B/</guid>
      <description>&lt;h2 id=&#34;编译源码&#34;&gt;编译源码&lt;/h2&gt;
&lt;h3 id=&#34;下载配置工具链&#34;&gt;下载配置工具链&lt;/h3&gt;
&lt;p&gt;访问&lt;a href=&#34;https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads&#34;&gt;ARM 官网下载工具链&lt;/a&gt;下载自己系统的版本的工具链。如果你也是 x86_64 的 Linux 系统，直接点击&lt;a href=&#34;https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz&#34;&gt;该链接下载 arm-gnu-toolchain-13.3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;解压工具链：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xz -d arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar -xvf arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将工具链路径添加到环境变量中。&lt;/p&gt;
&lt;h3 id=&#34;编译源码-1&#34;&gt;编译源码&lt;/h3&gt;
&lt;p&gt;源码使用 CMake 进行编译，CMake 版本需要 3.18.4 以上。如果你是 Ubuntu 20.04，直接安装即可。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install cmake
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你是 Ubuntu 18.04，需要升级 CMAKE。可以通过下面的方式下载源码编译安装 CMAKE。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget https://github.com/Kitware/CMake/releases/download/v3.22.0/cmake-3.22.0-linux-x86_64.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar -zxvf cmake-3.22.0-linux-x86_64.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv cmake-3.22.0-linux-x86_64 /usr/local/cmake
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/cmake/bin:&lt;span class=&#34;nv&#34;&gt;$PATH&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;源码编译：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make -f Makefile.cmake &lt;span class=&#34;nv&#34;&gt;PRODUCT&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;totalcompute/tc2 &lt;span class=&#34;nv&#34;&gt;MODE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;debug firmware-scp_ramfw
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;源码编译成功后，会在&lt;code&gt;build/tc2/GNU/debug/firmware-scp_ramfw/bin&lt;/code&gt;目录下生成二进制文件。具体编译参数，可以参考源码根目录下的&lt;code&gt;user_guide&lt;/code&gt;文档。&lt;/p&gt;
&lt;h2 id=&#34;初始化流程分析&#34;&gt;初始化流程分析&lt;/h2&gt;
&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;fwk_module_init-初始时module_config_table-是在什么时候被初始化的&#34;&gt;fwk_module_init 初始时，module_config_table 是在什么时候被初始化的？&lt;/h3&gt;
&lt;p&gt;module_config_table 无法在源码中直接搜索到，因为它是在编译过程中生成的，当你编译一次后，就会在 output/build/mpw/GNU/debug/firmware-scp_romfw/framework/src/fwk_module_list.c 找到这个变量。具体它是如何生成的，注意通过 &lt;code&gt;framework/CMakeLists.txt&lt;/code&gt; 文件中的这段代码完成，我们逐行分析这段代码。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;LENGTH&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_IDX_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取模块列表的长度，保存在 &lt;code&gt;SCP_MODULE_IDX_MAX&lt;/code&gt; 变量中。在每个 &lt;code&gt;Firmware.cmake&lt;/code&gt; 文件中，都会有一个 &lt;code&gt;SCP_MODULES&lt;/code&gt; 变量，这个变量保存了该产品所包含的模块。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# product/juno/scp_romfw/Firmware.cmake
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;uart&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当前我们加入了两个模块，所以 &lt;code&gt;SCP_MODULE_IDX_MAX&lt;/code&gt; 的值为 2。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;foreach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;idx&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;RANGE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SCP_MODULE_IDX_MAX&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;idx&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;EQUAL&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_IDX_MAX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_IDX_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;    FWK_MODULE_IDX_COUNT = ${idx},\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;endif&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;遍历模块列表，生成模块索引的定义，如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_idx&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_COUNT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;GET&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;idx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 &lt;code&gt;SCP_MODULES&lt;/code&gt; 列表中索引为 &lt;code&gt;idx&lt;/code&gt; 的元素赋值给变量 &lt;code&gt;SCP_MODULE&lt;/code&gt;，以便在后续的代码中使用。当前 &lt;code&gt;idx&lt;/code&gt; 为 0，所以 &lt;code&gt;SCP_MODULE&lt;/code&gt; 为 &lt;code&gt;test&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;MAKE_C_IDENTIFIER&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SCP_MODULE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;TOUPPER&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;SCP_MODULE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_UPPER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 &lt;code&gt;SCP_MODULE&lt;/code&gt; 转换为 C 标识符。将 &lt;code&gt;SCP_MODULE&lt;/code&gt; 转为大写并保存在 &lt;code&gt;SCP_MODULE_UPPER&lt;/code&gt; 中，即 &lt;code&gt;SCP_MODULE_UPPER=&amp;quot;TEST&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_IDX_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;    FWK_MODULE_IDX_${SCP_MODULE_UPPER} = ${idx},\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_ID_INIT_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;#define FWK_MODULE_ID_${SCP_MODULE_UPPER}_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_${SCP_MODULE_UPPER})\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_ID_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;#define FWK_MODULE_ID_${SCP_MODULE_UPPER} FWK_ID_MODULE(FWK_MODULE_IDX_${SCP_MODULE_UPPER})\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_ID_CONST_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;static const fwk_id_t fwk_module_id_${SCP_MODULE} = FWK_MODULE_ID_${SCP_MODULE_UPPER}_INIT;\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_EXTERN_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;extern const struct fwk_module module_${SCP_MODULE};\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_EXTERN_CONFIG_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;extern const struct fwk_module_config config_${SCP_MODULE};\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;    &amp;amp;module_${SCP_MODULE},\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULE_CONFIG_GEN&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;    &amp;amp;config_${SCP_MODULE},\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进行一些宏替换，替换后的结果如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-txt&#34; data-lang=&#34;txt&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SCP_MODULE_IDX_GEN: &amp;#34;   FWK_MODULE_IDX_TEST = 0,&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SCP_MODULE_ID_INIT_GEN: &amp;#34;#define FWK_MODULE_ID_TEST_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_TEST)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SCP_MODULE_ID_GEN: &amp;#34;#define FWK_MODULE_ID_TEST FWK_ID_MODULE(FWK_MODULE_IDX_TEST)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SCP_MODULE_ID_CONST_GEN: &amp;#34;static const fwk_id_t fwk_module_id_test = FWK_MODULE_ID_TEST_INIT;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SCP_MODULE_EXTERN_GEN: &amp;#34;extern const struct fwk_module module_test;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SCP_MODULE_EXTERN_CONFIG_GEN: &amp;#34;extern const struct fwk_module_config config_test;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SCP_MODULE_GEN: &amp;#34;&amp;amp;module_test,&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SCP_MODULE_CONFIG_GEN: &amp;#34;&amp;amp;config_test,&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;target_compile_definitions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;framework&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                               &lt;span class=&#34;s&#34;&gt;PUBLIC&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;BUILD_HAS_MOD_${SCP_MODULE_UPPER}=1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 &lt;code&gt;BUILD_HAS_MOD_TEST&lt;/code&gt; 定义为 1，以便在后续的代码中使用。&lt;/p&gt;
&lt;p&gt;在源码文件中有两个模板文件，分别为 &lt;code&gt;fwk_module_list.c.in&lt;/code&gt; 和 &lt;code&gt;fwk_module_idx.h.in&lt;/code&gt;，这两个文件中包含了一些宏定义，这些宏定义在编译过程中会被替换为上面生成的宏定义。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;stddef.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SCP_MODULE_EXTERN_GEN&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_COUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SCP_MODULE_GEN&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SCP_MODULE_EXTERN_CONFIG_GEN&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_config_table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_COUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SCP_MODULE_CONFIG_GEN&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;fwk_id.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SCP_MODULE_ID_INIT_GEN&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SCP_MODULE_ID_GEN&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_idx&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SCP_MODULE_IDX_GEN&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SCP_MODULE_ID_CONST_GEN&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在编译过程中就会生成下面两个文件，当使用&lt;code&gt;module_config_table&lt;/code&gt;时，就会引用这两个文件，找到对应的配置。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// build/mpw/GNU/debug/firmware-scp_romfw/framework/include/fwk_module_idx.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define FWK_MODULE_ID_TEST_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_TEST)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define FWK_MODULE_ID_UART_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_UART)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define FWK_MODULE_ID_TEST FWK_ID_MODULE(FWK_MODULE_IDX_TEST)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define FWK_MODULE_ID_UART FWK_ID_MODULE(FWK_MODULE_IDX_UART)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_idx&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_TEST&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_UART&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_COUNT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_id_test&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_MODULE_ID_TEST_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;fwk_id_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_id_uart&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FWK_MODULE_ID_UART_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// build/mpw/GNU/debug/firmware-scp_romfw/framework/src/fwk_module_list.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module_test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module_uart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_COUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_uart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_config&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_config&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_uart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fwk_module_config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module_config_table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FWK_MODULE_IDX_COUNT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config_test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config_uart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;如何确定各个模块在初始化过程中的执行顺序&#34;&gt;如何确定各个模块在初始化过程中的执行顺序？&lt;/h3&gt;
&lt;p&gt;在每个产品目录 mscp/product/juno/scp_romfw/Firmware.cmake 中，都会有一个 Firmware.cmake 文件，这个文件中会包含该产品所包含的模块：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;juno-ppu&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;juno-rom&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;gtimer&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sds&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;bootloader&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;APPEND&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;SCP_MODULES&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;juno-soc-clock&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译后会在 output 文件夹中生成&lt;code&gt;fwk_module_idx.h&lt;/code&gt;文件，这个文件中会包含所有模块的索引，如下：&lt;/p&gt;
&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="编译源码">编译源码</h2>
<h3 id="下载配置工具链">下载配置工具链</h3>
<p>访问<a href="https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads">ARM 官网下载工具链</a>下载自己系统的版本的工具链。如果你也是 x86_64 的 Linux 系统，直接点击<a href="https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz">该链接下载 arm-gnu-toolchain-13.3</a></p>
<p>解压工具链：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">xz -d arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz
</span></span><span class="line"><span class="cl">tar -xvf arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar
</span></span></code></pre></div><p>将工具链路径添加到环境变量中。</p>
<h3 id="编译源码-1">编译源码</h3>
<p>源码使用 CMake 进行编译，CMake 版本需要 3.18.4 以上。如果你是 Ubuntu 20.04，直接安装即可。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo apt install cmake
</span></span></code></pre></div><p>如果你是 Ubuntu 18.04，需要升级 CMAKE。可以通过下面的方式下载源码编译安装 CMAKE。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">wget https://github.com/Kitware/CMake/releases/download/v3.22.0/cmake-3.22.0-linux-x86_64.tar.gz
</span></span><span class="line"><span class="cl">tar -zxvf cmake-3.22.0-linux-x86_64.tar.gz
</span></span><span class="line"><span class="cl">mv cmake-3.22.0-linux-x86_64 /usr/local/cmake
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span>/usr/local/cmake/bin:<span class="nv">$PATH</span>
</span></span></code></pre></div><p>源码编译：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">make -f Makefile.cmake <span class="nv">PRODUCT</span><span class="o">=</span>totalcompute/tc2 <span class="nv">MODE</span><span class="o">=</span>debug firmware-scp_ramfw
</span></span></code></pre></div><p>源码编译成功后，会在<code>build/tc2/GNU/debug/firmware-scp_ramfw/bin</code>目录下生成二进制文件。具体编译参数，可以参考源码根目录下的<code>user_guide</code>文档。</p>
<h2 id="初始化流程分析">初始化流程分析</h2>
<p>

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="fwk_module_init-初始时module_config_table-是在什么时候被初始化的">fwk_module_init 初始时，module_config_table 是在什么时候被初始化的？</h3>
<p>module_config_table 无法在源码中直接搜索到，因为它是在编译过程中生成的，当你编译一次后，就会在 output/build/mpw/GNU/debug/firmware-scp_romfw/framework/src/fwk_module_list.c 找到这个变量。具体它是如何生成的，注意通过 <code>framework/CMakeLists.txt</code> 文件中的这段代码完成，我们逐行分析这段代码。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">LENGTH</span> <span class="s">SCP_MODULES</span> <span class="s">SCP_MODULE_IDX_MAX</span><span class="p">)</span><span class="err">
</span></span></span></code></pre></div><p>获取模块列表的长度，保存在 <code>SCP_MODULE_IDX_MAX</code> 变量中。在每个 <code>Firmware.cmake</code> 文件中，都会有一个 <code>SCP_MODULES</code> 变量，这个变量保存了该产品所包含的模块。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl"><span class="c"># product/juno/scp_romfw/Firmware.cmake
</span></span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULES</span> <span class="s2">&#34;test&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULES</span> <span class="s2">&#34;uart&#34;</span><span class="p">)</span><span class="err">
</span></span></span></code></pre></div><p>当前我们加入了两个模块，所以 <code>SCP_MODULE_IDX_MAX</code> 的值为 2。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl"><span class="nb">foreach</span><span class="p">(</span><span class="s">idx</span> <span class="s">RANGE</span> <span class="o">${</span><span class="nv">SCP_MODULE_IDX_MAX</span><span class="o">}</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">if</span><span class="p">(</span><span class="s">idx</span> <span class="s">EQUAL</span> <span class="s">SCP_MODULE_IDX_MAX</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">        <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_IDX_GEN</span> <span class="s2">&#34;    FWK_MODULE_IDX_COUNT = ${idx},\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl">        <span class="nb">break</span><span class="p">()</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">endif</span><span class="p">()</span><span class="err">
</span></span></span></code></pre></div><p>遍历模块列表，生成模块索引的定义，如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">enum</span> <span class="n">fwk_module_idx</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">FWK_MODULE_IDX_COUNT</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl">    <span class="nb">list</span><span class="p">(</span><span class="s">GET</span> <span class="s">SCP_MODULES</span> <span class="o">${</span><span class="nv">idx</span><span class="o">}</span> <span class="s">SCP_MODULE</span><span class="p">)</span><span class="err">
</span></span></span></code></pre></div><p>将 <code>SCP_MODULES</code> 列表中索引为 <code>idx</code> 的元素赋值给变量 <code>SCP_MODULE</code>，以便在后续的代码中使用。当前 <code>idx</code> 为 0，所以 <code>SCP_MODULE</code> 为 <code>test</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">MAKE_C_IDENTIFIER</span> <span class="o">${</span><span class="nv">SCP_MODULE</span><span class="o">}</span> <span class="s">SCP_MODULE</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">TOUPPER</span> <span class="o">${</span><span class="nv">SCP_MODULE</span><span class="o">}</span> <span class="s">SCP_MODULE_UPPER</span><span class="p">)</span><span class="err">
</span></span></span></code></pre></div><p>将 <code>SCP_MODULE</code> 转换为 C 标识符。将 <code>SCP_MODULE</code> 转为大写并保存在 <code>SCP_MODULE_UPPER</code> 中，即 <code>SCP_MODULE_UPPER=&quot;TEST&quot;</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_IDX_GEN</span> <span class="s2">&#34;    FWK_MODULE_IDX_${SCP_MODULE_UPPER} = ${idx},\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_ID_INIT_GEN</span> <span class="s2">&#34;#define FWK_MODULE_ID_${SCP_MODULE_UPPER}_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_${SCP_MODULE_UPPER})\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_ID_GEN</span> <span class="s2">&#34;#define FWK_MODULE_ID_${SCP_MODULE_UPPER} FWK_ID_MODULE(FWK_MODULE_IDX_${SCP_MODULE_UPPER})\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_ID_CONST_GEN</span> <span class="s2">&#34;static const fwk_id_t fwk_module_id_${SCP_MODULE} = FWK_MODULE_ID_${SCP_MODULE_UPPER}_INIT;\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_EXTERN_GEN</span> <span class="s2">&#34;extern const struct fwk_module module_${SCP_MODULE};\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_EXTERN_CONFIG_GEN</span> <span class="s2">&#34;extern const struct fwk_module_config config_${SCP_MODULE};\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_GEN</span> <span class="s2">&#34;    &amp;module_${SCP_MODULE},\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl">    <span class="nb">string</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULE_CONFIG_GEN</span> <span class="s2">&#34;    &amp;config_${SCP_MODULE},\n&#34;</span><span class="p">)</span><span class="err">
</span></span></span></code></pre></div><p>进行一些宏替换，替换后的结果如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">SCP_MODULE_IDX_GEN: &#34;   FWK_MODULE_IDX_TEST = 0,&#34;
</span></span><span class="line"><span class="cl">SCP_MODULE_ID_INIT_GEN: &#34;#define FWK_MODULE_ID_TEST_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_TEST)&#34;
</span></span><span class="line"><span class="cl">SCP_MODULE_ID_GEN: &#34;#define FWK_MODULE_ID_TEST FWK_ID_MODULE(FWK_MODULE_IDX_TEST)&#34;
</span></span><span class="line"><span class="cl">SCP_MODULE_ID_CONST_GEN: &#34;static const fwk_id_t fwk_module_id_test = FWK_MODULE_ID_TEST_INIT;&#34;
</span></span><span class="line"><span class="cl">SCP_MODULE_EXTERN_GEN: &#34;extern const struct fwk_module module_test;&#34;
</span></span><span class="line"><span class="cl">SCP_MODULE_EXTERN_CONFIG_GEN: &#34;extern const struct fwk_module_config config_test;&#34;
</span></span><span class="line"><span class="cl">SCP_MODULE_GEN: &#34;&amp;module_test,&#34;
</span></span><span class="line"><span class="cl">SCP_MODULE_CONFIG_GEN: &#34;&amp;config_test,&#34;
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl">    <span class="nb">target_compile_definitions</span><span class="p">(</span><span class="s">framework</span>
</span></span><span class="line"><span class="cl">                               <span class="s">PUBLIC</span> <span class="s2">&#34;BUILD_HAS_MOD_${SCP_MODULE_UPPER}=1&#34;</span><span class="p">)</span><span class="err">
</span></span></span></code></pre></div><p>将 <code>BUILD_HAS_MOD_TEST</code> 定义为 1，以便在后续的代码中使用。</p>
<p>在源码文件中有两个模板文件，分别为 <code>fwk_module_list.c.in</code> 和 <code>fwk_module_idx.h.in</code>，这两个文件中包含了一些宏定义，这些宏定义在编译过程中会被替换为上面生成的宏定义。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;stddef.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">SCP_MODULE_EXTERN_GEN</span><span class="err">@</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">struct</span> <span class="n">fwk_module</span> <span class="o">*</span><span class="n">module_table</span><span class="p">[</span><span class="n">FWK_MODULE_IDX_COUNT</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">SCP_MODULE_GEN</span><span class="err">@</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">SCP_MODULE_EXTERN_CONFIG_GEN</span><span class="err">@</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">struct</span> <span class="n">fwk_module_config</span> <span class="o">*</span><span class="n">module_config_table</span><span class="p">[</span><span class="n">FWK_MODULE_IDX_COUNT</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">SCP_MODULE_CONFIG_GEN</span><span class="err">@</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fwk_id.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">SCP_MODULE_ID_INIT_GEN</span><span class="err">@</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">SCP_MODULE_ID_GEN</span><span class="err">@</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="n">fwk_module_idx</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">SCP_MODULE_IDX_GEN</span><span class="err">@</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">@</span><span class="n">SCP_MODULE_ID_CONST_GEN</span><span class="err">@</span>
</span></span></code></pre></div><p>在编译过程中就会生成下面两个文件，当使用<code>module_config_table</code>时，就会引用这两个文件，找到对应的配置。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// build/mpw/GNU/debug/firmware-scp_romfw/framework/include/fwk_module_idx.h
</span></span></span><span class="line"><span class="cl"><span class="cp">#define FWK_MODULE_ID_TEST_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_TEST)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define FWK_MODULE_ID_UART_INIT FWK_ID_MODULE_INIT(FWK_MODULE_IDX_UART)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#define FWK_MODULE_ID_TEST FWK_ID_MODULE(FWK_MODULE_IDX_TEST)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define FWK_MODULE_ID_UART FWK_ID_MODULE(FWK_MODULE_IDX_UART)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">enum</span> <span class="n">fwk_module_idx</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">FWK_MODULE_IDX_TEST</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">FWK_MODULE_IDX_UART</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">FWK_MODULE_IDX_COUNT</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="kt">fwk_id_t</span> <span class="n">fwk_module_id_test</span> <span class="o">=</span> <span class="n">FWK_MODULE_ID_TEST_INIT</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="kt">fwk_id_t</span> <span class="n">fwk_module_id_uart</span> <span class="o">=</span> <span class="n">FWK_MODULE_ID_UART_INIT</span><span class="p">;</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// build/mpw/GNU/debug/firmware-scp_romfw/framework/src/fwk_module_list.c
</span></span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">fwk_module</span> <span class="n">module_test</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">fwk_module</span> <span class="n">module_uart</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">struct</span> <span class="n">fwk_module</span> <span class="o">*</span><span class="n">module_table</span><span class="p">[</span><span class="n">FWK_MODULE_IDX_COUNT</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">&amp;</span><span class="n">module_test</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="o">&amp;</span><span class="n">module_uart</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">fwk_module_config</span> <span class="n">config_test</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">fwk_module_config</span> <span class="n">config_uart</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="k">struct</span> <span class="n">fwk_module_config</span> <span class="o">*</span><span class="n">module_config_table</span><span class="p">[</span><span class="n">FWK_MODULE_IDX_COUNT</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="o">&amp;</span><span class="n">config_test</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="o">&amp;</span><span class="n">config_uart</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h3 id="如何确定各个模块在初始化过程中的执行顺序">如何确定各个模块在初始化过程中的执行顺序？</h3>
<p>在每个产品目录 mscp/product/juno/scp_romfw/Firmware.cmake 中，都会有一个 Firmware.cmake 文件，这个文件中会包含该产品所包含的模块：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-cmake" data-lang="cmake"><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULES</span> <span class="s2">&#34;juno-ppu&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULES</span> <span class="s2">&#34;juno-rom&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULES</span> <span class="s2">&#34;gtimer&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULES</span> <span class="s2">&#34;sds&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULES</span> <span class="s2">&#34;bootloader&#34;</span><span class="p">)</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="nb">list</span><span class="p">(</span><span class="s">APPEND</span> <span class="s">SCP_MODULES</span> <span class="s2">&#34;juno-soc-clock&#34;</span><span class="p">)</span><span class="err">
</span></span></span></code></pre></div><p>编译后会在 output 文件夹中生成<code>fwk_module_idx.h</code>文件，这个文件中会包含所有模块的索引，如下：</p>
<p>

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>BusyBox 构建并启动 RISC-V Linux 内核</title>
      <link>https://lifeislife.cn/posts/busybox-%E6%9E%84%E5%BB%BA%E5%B9%B6%E5%90%AF%E5%8A%A8-risc-v-linux-%E5%86%85%E6%A0%B8/</link>
      <pubDate>Thu, 20 Jun 2024 21:10:49 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/busybox-%E6%9E%84%E5%BB%BA%E5%B9%B6%E5%90%AF%E5%8A%A8-risc-v-linux-%E5%86%85%E6%A0%B8/</guid>
      <description>&lt;h1 id=&#34;根文件系统&#34;&gt;根文件系统&lt;/h1&gt;
&lt;h2 id=&#34;文件系统与根文件系统&#34;&gt;文件系统与根文件系统&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;文件系统&lt;/strong&gt;（File System）是操作系统用于管理和存储数据的一种方式。它定义了如何在存储设备（如硬盘、SSD、USB 驱动器等）上组织文件和目录，以及如何进行数据的读写操作。&lt;/p&gt;
&lt;p&gt;常见的文件系统类型有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ext4：Linux 最常用的文件系统，支持大文件和大分区。&lt;/li&gt;
&lt;li&gt;NTFS：Windows 操作系统常用的文件系统，支持文件加密和权限控制。&lt;/li&gt;
&lt;li&gt;FAT32：一种兼容性广泛的文件系统，常用于 USB 驱动器和内存卡。&lt;/li&gt;
&lt;li&gt;XFS：适用于高性能和高容量存储需求的文件系统。&lt;/li&gt;
&lt;li&gt;btrfs：一种现代 Linux 文件系统，支持快照、压缩和多设备管理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;根文件系统&lt;/strong&gt;（Root File System，通常简称为 rootfs）是文件系统层次结构中的顶级文件系统。它包含了操作系统启动和运行所需的所有基本文件和目录。根文件系统是整个文件系统层次的起点，在 Linux 中由单个斜杠（&lt;code&gt;/&lt;/code&gt;）表示。&lt;strong&gt;根文件系统首先是内核启动时所 mount 的第一个文件系统&lt;/strong&gt;，内核代码映像文件保存在根文件系统中，而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;根文件系统是建立在文件系统之上的。根文件系统使用某种具体的文件系统类型（如 ext4）来管理和存储其内容。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;基于内存的文件系统&#34;&gt;基于内存的文件系统&lt;/h2&gt;
&lt;p&gt;ramdisk 是一种基于内存的文件系统，它将内存的一部分用作硬盘驱动器，这样就可以在内存中创建一个文件系统。ramdisk 是一个虚拟磁盘，它的大小和硬盘驱动器的大小一样。ramdisk 的优点是速度快，缺点是断电后数据丢失。&lt;/p&gt;
&lt;h2 id=&#34;根文件系统中各种配置文件的作用以及配置文件的格式介绍&#34;&gt;根文件系统中各种配置文件的作用以及配置文件的格式介绍&lt;/h2&gt;
&lt;h3 id=&#34;etcinittab&#34;&gt;/etc/inittab&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;/etc/inittab&lt;/code&gt; 是 Linux 系统中的一个配置文件，它是 init 程序的配置文件，用于配置系统的运行级别和 init 程序的行为。在 Linux 系统中，init 程序是系统的第一个进程，它负责启动系统中的所有其他进程。&lt;code&gt;/etc/inittab&lt;/code&gt; 文件中的每一行都是一个配置项，每个配置项由四个字段组成，字段之间用空格或制表符分隔。&lt;code&gt;/etc/inittab&lt;/code&gt; 文件的格式如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;id:runlevels:action:process
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个字段用冒号分隔，可以缺省。各字段的含义如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;id：配置项的标识符，用于标识配置项。&lt;/li&gt;
&lt;li&gt;runlevels：配置项所对应的运行级别，可以是一个或多个运行级别的组合。&lt;/li&gt;
&lt;li&gt;action：配置项的动作，可以是以下几种动作之一：
&lt;ul&gt;
&lt;li&gt;sysinit：系统初始化时运行。&lt;/li&gt;
&lt;li&gt;respawn：如果进程终止，立即重新启动。&lt;/li&gt;
&lt;li&gt;askfirst：在运行 process 之前询问用户。并在控制台上显示 Please press Enter to active this console。&lt;/li&gt;
&lt;li&gt;wait：等待进程终止，然后继续执行下一个配置项。&lt;/li&gt;
&lt;li&gt;once：只运行一次，进程终止后不会重新启动。&lt;/li&gt;
&lt;li&gt;boot：在系统引导时运行。&lt;/li&gt;
&lt;li&gt;bootwait：在系统引导时运行，等待进程终止后继续引导。&lt;/li&gt;
&lt;li&gt;initdefault：设置默认运行级别。&lt;/li&gt;
&lt;li&gt;shutdown：在系统关机时运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;process：要执行的进程或脚本的路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /etc/inittab&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#系统开机或重新启动，执行rcS文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::sysinit:/etc/init.d/rcS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#系统启动后，运行登录程序  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::askfirst:-/bin/login
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#按下组合键“ctrl+alt+del”，重启Linux系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::ctrlaltdel:-/sbin/reboot   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#系统关机时，卸载所有文件系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::shutdown:/bin/umount -a -r
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#重启init进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::restart:/sbin/init
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;etcfstab&#34;&gt;/etc/fstab&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;/etc/fstab&lt;/code&gt; 是 Linux 系统中的一个配置文件，用于配置文件系统的挂载信息。在 Linux 系统中，文件系统是通过挂载的方式来访问的，&lt;code&gt;/etc/fstab&lt;/code&gt; 文件中记录了系统中所有文件系统的挂载信息。&lt;code&gt;/etc/fstab&lt;/code&gt; 文件的格式如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;device mount_point fs_type options dump pass
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各字段的含义如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;device：设备文件或 UUID。&lt;/li&gt;
&lt;li&gt;mount_point：挂载点。&lt;/li&gt;
&lt;li&gt;fs_type：文件系统类型。&lt;/li&gt;
&lt;li&gt;options：挂载选项。&lt;/li&gt;
&lt;li&gt;dump：备份标志，用于备份工具。&lt;/li&gt;
&lt;li&gt;pass：文件系统检查顺序。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /etc/fstab&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# &amp;lt;文件系统&amp;gt;  &amp;lt;挂载点&amp;gt;  &amp;lt;类型&amp;gt;  &amp;lt;选项&amp;gt;        &amp;lt;dump&amp;gt;  &amp;lt;fsck&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 根文件系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda1       /           ext4    defaults        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# 根分区，使用 ext4 文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /boot 分区，用于存放引导加载程序和内核镜像&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda2       /boot       ext4    defaults        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# /boot 分区，使用 ext4 文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 交换分区，用作虚拟内存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda3       none        swap    sw              &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# 交换分区，不需要挂载点，使用 swap 类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /home 分区，用于存放用户的个人数据&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda4       /home       ext4    defaults        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# /home 分区，使用 ext4 文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /tmp 分区，用于存放临时文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda5       /tmp        ext4    defaults        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# /tmp 分区，使用 ext4 文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /var 分区，用于存放可变数据文件，如日志、邮件、缓存等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda6       /var        ext4    defaults        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# /var 分区，使用 ext4 文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /mnt/data 分区，用于存放额外的数据文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/dev/sda7       /mnt/data   ext4    defaults        &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# /mnt/data 分区，使用 ext4 文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载 proc 文件系统，用于访问进程和系统信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;proc            /proc       proc    defaults        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# proc 虚拟文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载 sysfs 文件系统，用于访问设备和内核信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sysfs           /sys        sysfs   defaults        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# sysfs 虚拟文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载 tmpfs 文件系统，用于临时文件存储&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tmpfs           /dev/shm    tmpfs   defaults        &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# tmpfs 虚拟文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载 devpts 文件系统，用于伪终端设备&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;devpts          /dev/pts    devpts  &lt;span class=&#34;nv&#34;&gt;gid&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;5,mode&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;620&lt;/span&gt;  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;       &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# devpts 虚拟文件系统，默认挂载选项&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;etcinitdrcs&#34;&gt;/etc/init.d/rcS&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;/etc/init.d/rcS&lt;/code&gt; 是 Linux 系统中的一个初始化脚本，用于系统初始化时运行。在 Linux 系统中，&lt;code&gt;/etc/init.d/rcS&lt;/code&gt; 脚本是系统初始化时运行的第一个脚本，它负责初始化系统中的各种服务和配置。&lt;code&gt;/etc/init.d/rcS&lt;/code&gt; 脚本通常包含了一些初始化命令，如加载模块、挂载文件系统、启动服务等。&lt;code&gt;/etc/init.d/rcS&lt;/code&gt; 脚本的格式如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 这行是 shebang，用于指定这个脚本将由 /bin/sh 解释执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载 proc 文件系统到 /proc 目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mount -t proc none /proc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# proc 文件系统是一个虚拟文件系统，用于提供内核和进程的信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载 sysfs 文件系统到 /sys 目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mount -t sysfs none /sys
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# sysfs 文件系统是一个虚拟文件系统，用于提供设备和内核信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载 devtmpfs 文件系统到 /dev 目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mount -t devtmpfs none /dev
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# devtmpfs 是一个用于设备节点的临时文件系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 运行 mdev 以创建设备节点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/sbin/mdev -s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# mdev 是一个轻量级的设备管理工具，用于创建和管理 /dev 目录中的设备节点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 设置主机名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;myhostname&amp;#34;&lt;/span&gt; &amp;gt; /proc/sys/kernel/hostname
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 将主机名设置为 &amp;#34;myhostname&amp;#34;，这个名字可以根据需要更改&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 启动网络接口配置脚本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ifconfig lo up
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 启动回环接口 lo，这是一个特殊的网络接口，用于网络软件本地通信&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 运行所有位于 /etc/init.d/ 目录中的初始化脚本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; script in /etc/init.d/S*&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; -x &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$script&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$script&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; start
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 遍历 /etc/init.d/ 目录中的所有以 S 开头的脚本，并执行它们以启动相应的服务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# -x 选项用于检查文件是否可执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载用户文件系统（可选，根据实际需要）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mount -a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 挂载 /etc/fstab 文件中列出的所有文件系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 打印启动完成信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;System initialization complete.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输出系统初始化完成信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;etcprofile&#34;&gt;/etc/profile&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;/etc/profile&lt;/code&gt; 是 Linux 系统中的一个全局配置文件，用于配置系统的环境变量和用户的 shell 环境。在 Linux 系统中，&lt;code&gt;/etc/profile&lt;/code&gt; 文件是系统启动时加载的第一个配置文件，它包含了系统的全局环境变量和用户的 shell 环境配置。&lt;code&gt;/etc/profile&lt;/code&gt; 文件的格式如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /etc/profile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#!/bin/sh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 这行是 shebang，用于指定这个脚本将由 /bin/sh 解释执行&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 设置 PATH 环境变量，定义系统命令的搜索路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; PATH
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /usr/local/sbin:/usr/local/bin 是系统管理员和用户安装的程序路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /sbin:/bin:/usr/sbin:/usr/bin 是系统默认的命令路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 设置用户 umask，定义新文件和目录的默认权限掩码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;umask&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;022&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# umask 022 表示新文件的默认权限是 755，新目录的默认权限是 644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 设置系统语言和区域&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LANG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;en_US.UTF-8&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; LANG
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# LANG 变量定义了系统的语言环境，这里设置为美国英语 UTF-8 编码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 设置历史记录文件和大小&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;HISTSIZE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;HISTFILESIZE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; HISTSIZE HISTFILESIZE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# HISTSIZE 定义了 shell 会话历史记录的条目数，HISTFILESIZE 定义了历史记录文件的最大条目数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 系统启动信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Welcome to your Linux system!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 在用户登录时显示欢迎信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 读取并执行 /etc/bashrc（如果存在）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; -f /etc/bashrc &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    . /etc/bashrc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# /etc/bashrc 是另一个全局配置文件，通常包含 bash shell 的配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 使用 . /etc/bashrc 命令将其内容导入当前 shell 环境&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 配置别名（示例）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;ll&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ls -l&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;la&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ls -A&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;alias&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;l&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ls -CF&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 定义一些常用命令的别名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# ll 代表 ls -l，显示详细列表&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# la 代表 ls -A，显示所有文件包括隐藏文件（但不包括 . 和 ..）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# l 代表 ls -CF，以分类格式显示文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 读取用户特定的配置文件（如果存在）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt; -f &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$HOME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/.profile&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    . &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$HOME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/.profile&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# .profile 是用户的个人配置文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 使用 . $HOME/.profile 命令将其内容导入当前 shell 环境&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 设置编辑器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;EDITOR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;vim
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; EDITOR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 定义默认的文本编辑器为 vim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 设置主机名显示，也就是终端最前面提示符的样式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PS1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;\u@\h:\w\$ &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; PS1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# PS1 定义了 shell 提示符的样式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# \u 代表用户名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# \h 代表主机名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# \w 代表当前工作目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;busybox-简介以及如何制作-busybox-文件系统&#34;&gt;Busybox 简介以及如何制作 Busybox 文件系统&lt;/h2&gt;
&lt;h3 id=&#34;准备-qemu&#34;&gt;准备 QEMU&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; mkdir -p /home/user/program/riscv64-qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; workspace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/qemu/qemu.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; qemu &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./configure --target-list&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv32-softmmu,riscv32-linux-user,riscv64-linux-user,riscv64-softmmu &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               --enable-kvm --enable-sdl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               --prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/home/user/program/riscv64-qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make install -j &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;nproc&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;准备-opensbi&#34;&gt;准备 OpenSBI&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; workspace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/riscv-software-src/opensbi.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; opensbi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;ARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- &lt;span class=&#34;nv&#34;&gt;PLATFORM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;generic
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;准备-linux-内核&#34;&gt;准备 Linux 内核&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; workspace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/torvalds/linux.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;ARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- defconfig
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;ARCH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- -j &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;nproc&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;准备-busybox&#34;&gt;准备 Busybox&lt;/h3&gt;
&lt;p&gt;进入下载软件包，&lt;a href=&#34;https://busybox.net/downloads/&#34;&gt;https://busybox.net/downloads/&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar -xvf busybox-1.36.1.tar.bz2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv busybox-1.36.1 busybox
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; busybox
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置编译选项&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- menuconfig
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;选择静态库模式，设置路径：Settings -&amp;gt; Build static binary (no shared libs)&lt;/p&gt;
&lt;p&gt;

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

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

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;编译 Busybox&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- -j &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;nproc&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;如果需要频繁编译，也可以在 Menuconfig 中设置交叉编译器路径，这样就不需要每次都指定了。设置路径为：Settings -&amp;gt; Build Options -&amp;gt; Cross Compiler prefix。将其设置为 riscv64-unknown-linux-gnu-。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;安装 Busybox：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;CROSS_COMPILE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv64-unknown-linux-gnu- install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;Busybox 默认安装在当前目录的_install 目录下，也可以在 Menuconfig 中设置安装目录，路径为：Settings -&amp;gt; Build Options -&amp;gt; Destination path for &amp;lsquo;make install&amp;rsquo;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;查看安装目录&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls _install 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bin  linuxrc  sbin  usr
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;制作根文件系统&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;qemu-img create -f raw rootfs.img 256M
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkfs.ext4 rootfs.img
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir rootfs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo mount -o loop rootfs.img rootfs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo cp -r _install/* rootfs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; rootfs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo mkdir proc sys dev etc etc/init.d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; etc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; init.d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo touch rcS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo chmod +x rcS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo vim rcS
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;写入以下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mount -t proc none /proc  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mount -t sysfs none /sys  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/sbin/mdev -s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo umount rootfs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;qemu 启动内核：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -en &lt;span class=&#34;s1&#34;&gt;&amp;#39;\001\033[0m\002&amp;#39;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -en &lt;span class=&#34;s1&#34;&gt;&amp;#39;\001\033[00;33m\002&amp;#39;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;## Configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;vcpu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;memory&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;drive&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/user/workspace/rootfs.img&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;kernel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; /home/user/workspace/linux-stable/arch/riscv/boot/Image&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;fw&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/user/workspace/opensbi/build/platform/generic/firmware/fw_jump.bin&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;ssh_port&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;12070&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;cmd&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/user/program/riscv64-qemu/bin/qemu-system-riscv64 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;  -nographic -machine virt \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;  -smp &amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$vcpu&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; -m &amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$memory&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;G \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;  -cpu rv64\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;  -bios &amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$fw&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;  -kernel &amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$kernel&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;  -drive file=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$drive&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;,format=raw,id=hd0 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;  -device virtio-blk-device,drive=hd0 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;  -append &amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;root&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/dev/vda &lt;span class=&#34;nv&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;ttyS0&lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;:: Starting VM...&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;:: Using following configuration&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;vCPU Cores: &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$vcpu&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;Memory: &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$memory&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;G&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;Disk: &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$drive&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;SSH Port: &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$ssh_port&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;:: NOTE: Make sure ONLY ONE .qcow2 file is&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;in the current directory&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;:: Tip: Try setting DNS manually &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; QEMU user network doesn&lt;span class=&#34;se&#34;&gt;\&amp;#39;&lt;/span&gt;t work well. &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;YELLOW&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;:: HOWTO -&lt;span class=&#34;se&#34;&gt;\&amp;gt;&lt;/span&gt; https://serverfault.com/a/810639 &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;RESTORE&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sleep &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$cmd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="根文件系统">根文件系统</h1>
<h2 id="文件系统与根文件系统">文件系统与根文件系统</h2>
<p><strong>文件系统</strong>（File System）是操作系统用于管理和存储数据的一种方式。它定义了如何在存储设备（如硬盘、SSD、USB 驱动器等）上组织文件和目录，以及如何进行数据的读写操作。</p>
<p>常见的文件系统类型有：</p>
<ul>
<li>ext4：Linux 最常用的文件系统，支持大文件和大分区。</li>
<li>NTFS：Windows 操作系统常用的文件系统，支持文件加密和权限控制。</li>
<li>FAT32：一种兼容性广泛的文件系统，常用于 USB 驱动器和内存卡。</li>
<li>XFS：适用于高性能和高容量存储需求的文件系统。</li>
<li>btrfs：一种现代 Linux 文件系统，支持快照、压缩和多设备管理。</li>
</ul>
<p><strong>根文件系统</strong>（Root File System，通常简称为 rootfs）是文件系统层次结构中的顶级文件系统。它包含了操作系统启动和运行所需的所有基本文件和目录。根文件系统是整个文件系统层次的起点，在 Linux 中由单个斜杠（<code>/</code>）表示。<strong>根文件系统首先是内核启动时所 mount 的第一个文件系统</strong>，内核代码映像文件保存在根文件系统中，而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。</p>
<p><strong>根文件系统是建立在文件系统之上的。根文件系统使用某种具体的文件系统类型（如 ext4）来管理和存储其内容。</strong></p>
<h2 id="基于内存的文件系统">基于内存的文件系统</h2>
<p>ramdisk 是一种基于内存的文件系统，它将内存的一部分用作硬盘驱动器，这样就可以在内存中创建一个文件系统。ramdisk 是一个虚拟磁盘，它的大小和硬盘驱动器的大小一样。ramdisk 的优点是速度快，缺点是断电后数据丢失。</p>
<h2 id="根文件系统中各种配置文件的作用以及配置文件的格式介绍">根文件系统中各种配置文件的作用以及配置文件的格式介绍</h2>
<h3 id="etcinittab">/etc/inittab</h3>
<p><code>/etc/inittab</code> 是 Linux 系统中的一个配置文件，它是 init 程序的配置文件，用于配置系统的运行级别和 init 程序的行为。在 Linux 系统中，init 程序是系统的第一个进程，它负责启动系统中的所有其他进程。<code>/etc/inittab</code> 文件中的每一行都是一个配置项，每个配置项由四个字段组成，字段之间用空格或制表符分隔。<code>/etc/inittab</code> 文件的格式如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">id:runlevels:action:process
</span></span></code></pre></div><p>每个字段用冒号分隔，可以缺省。各字段的含义如下：</p>
<ul>
<li>id：配置项的标识符，用于标识配置项。</li>
<li>runlevels：配置项所对应的运行级别，可以是一个或多个运行级别的组合。</li>
<li>action：配置项的动作，可以是以下几种动作之一：
<ul>
<li>sysinit：系统初始化时运行。</li>
<li>respawn：如果进程终止，立即重新启动。</li>
<li>askfirst：在运行 process 之前询问用户。并在控制台上显示 Please press Enter to active this console。</li>
<li>wait：等待进程终止，然后继续执行下一个配置项。</li>
<li>once：只运行一次，进程终止后不会重新启动。</li>
<li>boot：在系统引导时运行。</li>
<li>bootwait：在系统引导时运行，等待进程终止后继续引导。</li>
<li>initdefault：设置默认运行级别。</li>
<li>shutdown：在系统关机时运行。</li>
</ul>
</li>
<li>process：要执行的进程或脚本的路径。</li>
</ul>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># /etc/inittab</span>
</span></span><span class="line"><span class="cl"><span class="c1">#系统开机或重新启动，执行rcS文件</span>
</span></span><span class="line"><span class="cl">::sysinit:/etc/init.d/rcS
</span></span><span class="line"><span class="cl"><span class="c1">#系统启动后，运行登录程序  </span>
</span></span><span class="line"><span class="cl">::askfirst:-/bin/login
</span></span><span class="line"><span class="cl"><span class="c1">#按下组合键“ctrl+alt+del”，重启Linux系统</span>
</span></span><span class="line"><span class="cl">::ctrlaltdel:-/sbin/reboot   
</span></span><span class="line"><span class="cl"><span class="c1">#系统关机时，卸载所有文件系统</span>
</span></span><span class="line"><span class="cl">::shutdown:/bin/umount -a -r
</span></span><span class="line"><span class="cl"><span class="c1">#重启init进程</span>
</span></span><span class="line"><span class="cl">::restart:/sbin/init
</span></span></code></pre></div><h3 id="etcfstab">/etc/fstab</h3>
<p><code>/etc/fstab</code> 是 Linux 系统中的一个配置文件，用于配置文件系统的挂载信息。在 Linux 系统中，文件系统是通过挂载的方式来访问的，<code>/etc/fstab</code> 文件中记录了系统中所有文件系统的挂载信息。<code>/etc/fstab</code> 文件的格式如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">device mount_point fs_type options dump pass
</span></span></code></pre></div><p>各字段的含义如下：</p>
<ul>
<li>device：设备文件或 UUID。</li>
<li>mount_point：挂载点。</li>
<li>fs_type：文件系统类型。</li>
<li>options：挂载选项。</li>
<li>dump：备份标志，用于备份工具。</li>
<li>pass：文件系统检查顺序。</li>
</ul>
<p>示例：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># /etc/fstab</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &lt;文件系统&gt;  &lt;挂载点&gt;  &lt;类型&gt;  &lt;选项&gt;        &lt;dump&gt;  &lt;fsck&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 根文件系统</span>
</span></span><span class="line"><span class="cl">/dev/sda1       /           ext4    defaults        <span class="m">1</span>       <span class="m">1</span>  <span class="c1"># 根分区，使用 ext4 文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># /boot 分区，用于存放引导加载程序和内核镜像</span>
</span></span><span class="line"><span class="cl">/dev/sda2       /boot       ext4    defaults        <span class="m">1</span>       <span class="m">2</span>  <span class="c1"># /boot 分区，使用 ext4 文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 交换分区，用作虚拟内存</span>
</span></span><span class="line"><span class="cl">/dev/sda3       none        swap    sw              <span class="m">0</span>       <span class="m">0</span>  <span class="c1"># 交换分区，不需要挂载点，使用 swap 类型</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># /home 分区，用于存放用户的个人数据</span>
</span></span><span class="line"><span class="cl">/dev/sda4       /home       ext4    defaults        <span class="m">1</span>       <span class="m">2</span>  <span class="c1"># /home 分区，使用 ext4 文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># /tmp 分区，用于存放临时文件</span>
</span></span><span class="line"><span class="cl">/dev/sda5       /tmp        ext4    defaults        <span class="m">1</span>       <span class="m">2</span>  <span class="c1"># /tmp 分区，使用 ext4 文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># /var 分区，用于存放可变数据文件，如日志、邮件、缓存等</span>
</span></span><span class="line"><span class="cl">/dev/sda6       /var        ext4    defaults        <span class="m">1</span>       <span class="m">2</span>  <span class="c1"># /var 分区，使用 ext4 文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># /mnt/data 分区，用于存放额外的数据文件</span>
</span></span><span class="line"><span class="cl">/dev/sda7       /mnt/data   ext4    defaults        <span class="m">1</span>       <span class="m">2</span>  <span class="c1"># /mnt/data 分区，使用 ext4 文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载 proc 文件系统，用于访问进程和系统信息</span>
</span></span><span class="line"><span class="cl">proc            /proc       proc    defaults        <span class="m">0</span>       <span class="m">0</span>  <span class="c1"># proc 虚拟文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载 sysfs 文件系统，用于访问设备和内核信息</span>
</span></span><span class="line"><span class="cl">sysfs           /sys        sysfs   defaults        <span class="m">0</span>       <span class="m">0</span>  <span class="c1"># sysfs 虚拟文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载 tmpfs 文件系统，用于临时文件存储</span>
</span></span><span class="line"><span class="cl">tmpfs           /dev/shm    tmpfs   defaults        <span class="m">0</span>       <span class="m">0</span>  <span class="c1"># tmpfs 虚拟文件系统，默认挂载选项</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载 devpts 文件系统，用于伪终端设备</span>
</span></span><span class="line"><span class="cl">devpts          /dev/pts    devpts  <span class="nv">gid</span><span class="o">=</span>5,mode<span class="o">=</span><span class="m">620</span>  <span class="m">0</span>       <span class="m">0</span>  <span class="c1"># devpts 虚拟文件系统，默认挂载选项</span>
</span></span></code></pre></div><h3 id="etcinitdrcs">/etc/init.d/rcS</h3>
<p><code>/etc/init.d/rcS</code> 是 Linux 系统中的一个初始化脚本，用于系统初始化时运行。在 Linux 系统中，<code>/etc/init.d/rcS</code> 脚本是系统初始化时运行的第一个脚本，它负责初始化系统中的各种服务和配置。<code>/etc/init.d/rcS</code> 脚本通常包含了一些初始化命令，如加载模块、挂载文件系统、启动服务等。<code>/etc/init.d/rcS</code> 脚本的格式如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="cp">#!/bin/sh
</span></span></span><span class="line"><span class="cl"><span class="c1"># 这行是 shebang，用于指定这个脚本将由 /bin/sh 解释执行</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载 proc 文件系统到 /proc 目录</span>
</span></span><span class="line"><span class="cl">mount -t proc none /proc
</span></span><span class="line"><span class="cl"><span class="c1"># proc 文件系统是一个虚拟文件系统，用于提供内核和进程的信息</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载 sysfs 文件系统到 /sys 目录</span>
</span></span><span class="line"><span class="cl">mount -t sysfs none /sys
</span></span><span class="line"><span class="cl"><span class="c1"># sysfs 文件系统是一个虚拟文件系统，用于提供设备和内核信息</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载 devtmpfs 文件系统到 /dev 目录</span>
</span></span><span class="line"><span class="cl">mount -t devtmpfs none /dev
</span></span><span class="line"><span class="cl"><span class="c1"># devtmpfs 是一个用于设备节点的临时文件系统</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 运行 mdev 以创建设备节点</span>
</span></span><span class="line"><span class="cl">/sbin/mdev -s
</span></span><span class="line"><span class="cl"><span class="c1"># mdev 是一个轻量级的设备管理工具，用于创建和管理 /dev 目录中的设备节点</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置主机名</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;myhostname&#34;</span> &gt; /proc/sys/kernel/hostname
</span></span><span class="line"><span class="cl"><span class="c1"># 将主机名设置为 &#34;myhostname&#34;，这个名字可以根据需要更改</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 启动网络接口配置脚本</span>
</span></span><span class="line"><span class="cl">ifconfig lo up
</span></span><span class="line"><span class="cl"><span class="c1"># 启动回环接口 lo，这是一个特殊的网络接口，用于网络软件本地通信</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 运行所有位于 /etc/init.d/ 目录中的初始化脚本</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> script in /etc/init.d/S*<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="o">[</span> -x <span class="s2">&#34;</span><span class="nv">$script</span><span class="s2">&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;</span><span class="nv">$script</span><span class="s2">&#34;</span> start
</span></span><span class="line"><span class="cl">  <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 遍历 /etc/init.d/ 目录中的所有以 S 开头的脚本，并执行它们以启动相应的服务</span>
</span></span><span class="line"><span class="cl"><span class="c1"># -x 选项用于检查文件是否可执行</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载用户文件系统（可选，根据实际需要）</span>
</span></span><span class="line"><span class="cl">mount -a
</span></span><span class="line"><span class="cl"><span class="c1"># 挂载 /etc/fstab 文件中列出的所有文件系统</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 打印启动完成信息</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;System initialization complete.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 输出系统初始化完成信息</span>
</span></span></code></pre></div><h3 id="etcprofile">/etc/profile</h3>
<p><code>/etc/profile</code> 是 Linux 系统中的一个全局配置文件，用于配置系统的环境变量和用户的 shell 环境。在 Linux 系统中，<code>/etc/profile</code> 文件是系统启动时加载的第一个配置文件，它包含了系统的全局环境变量和用户的 shell 环境配置。<code>/etc/profile</code> 文件的格式如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># /etc/profile</span>
</span></span><span class="line"><span class="cl"><span class="c1">#!/bin/sh</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 这行是 shebang，用于指定这个脚本将由 /bin/sh 解释执行</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置 PATH 环境变量，定义系统命令的搜索路径</span>
</span></span><span class="line"><span class="cl"><span class="nv">PATH</span><span class="o">=</span><span class="s2">&#34;/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> PATH
</span></span><span class="line"><span class="cl"><span class="c1"># /usr/local/sbin:/usr/local/bin 是系统管理员和用户安装的程序路径</span>
</span></span><span class="line"><span class="cl"><span class="c1"># /sbin:/bin:/usr/sbin:/usr/bin 是系统默认的命令路径</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置用户 umask，定义新文件和目录的默认权限掩码</span>
</span></span><span class="line"><span class="cl"><span class="nb">umask</span> <span class="m">022</span>
</span></span><span class="line"><span class="cl"><span class="c1"># umask 022 表示新文件的默认权限是 755，新目录的默认权限是 644</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置系统语言和区域</span>
</span></span><span class="line"><span class="cl"><span class="nv">LANG</span><span class="o">=</span><span class="s2">&#34;en_US.UTF-8&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> LANG
</span></span><span class="line"><span class="cl"><span class="c1"># LANG 变量定义了系统的语言环境，这里设置为美国英语 UTF-8 编码</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置历史记录文件和大小</span>
</span></span><span class="line"><span class="cl"><span class="nv">HISTSIZE</span><span class="o">=</span><span class="m">1000</span>
</span></span><span class="line"><span class="cl"><span class="nv">HISTFILESIZE</span><span class="o">=</span><span class="m">2000</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> HISTSIZE HISTFILESIZE
</span></span><span class="line"><span class="cl"><span class="c1"># HISTSIZE 定义了 shell 会话历史记录的条目数，HISTFILESIZE 定义了历史记录文件的最大条目数</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 系统启动信息</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Welcome to your Linux system!&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 在用户登录时显示欢迎信息</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 读取并执行 /etc/bashrc（如果存在）</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -f /etc/bashrc <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    . /etc/bashrc
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="c1"># /etc/bashrc 是另一个全局配置文件，通常包含 bash shell 的配置</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 使用 . /etc/bashrc 命令将其内容导入当前 shell 环境</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 配置别名（示例）</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">ll</span><span class="o">=</span><span class="s1">&#39;ls -l&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">la</span><span class="o">=</span><span class="s1">&#39;ls -A&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">alias</span> <span class="nv">l</span><span class="o">=</span><span class="s1">&#39;ls -CF&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 定义一些常用命令的别名</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ll 代表 ls -l，显示详细列表</span>
</span></span><span class="line"><span class="cl"><span class="c1"># la 代表 ls -A，显示所有文件包括隐藏文件（但不包括 . 和 ..）</span>
</span></span><span class="line"><span class="cl"><span class="c1"># l 代表 ls -CF，以分类格式显示文件</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 读取用户特定的配置文件（如果存在）</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="o">[</span> -f <span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.profile&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    . <span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.profile&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="c1"># .profile 是用户的个人配置文件</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 使用 . $HOME/.profile 命令将其内容导入当前 shell 环境</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置编辑器</span>
</span></span><span class="line"><span class="cl"><span class="nv">EDITOR</span><span class="o">=</span>vim
</span></span><span class="line"><span class="cl"><span class="nb">export</span> EDITOR
</span></span><span class="line"><span class="cl"><span class="c1"># 定义默认的文本编辑器为 vim</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 设置主机名显示，也就是终端最前面提示符的样式</span>
</span></span><span class="line"><span class="cl"><span class="nv">PS1</span><span class="o">=</span><span class="s1">&#39;\u@\h:\w\$ &#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> PS1
</span></span><span class="line"><span class="cl"><span class="c1"># PS1 定义了 shell 提示符的样式</span>
</span></span><span class="line"><span class="cl"><span class="c1"># \u 代表用户名</span>
</span></span><span class="line"><span class="cl"><span class="c1"># \h 代表主机名</span>
</span></span><span class="line"><span class="cl"><span class="c1"># \w 代表当前工作目录</span>
</span></span></code></pre></div><h2 id="busybox-简介以及如何制作-busybox-文件系统">Busybox 简介以及如何制作 Busybox 文件系统</h2>
<h3 id="准备-qemu">准备 QEMU</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="o">&amp;&amp;</span> mkdir -p /home/user/program/riscv64-qemu
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> workspace
</span></span><span class="line"><span class="cl">git clone https://github.com/qemu/qemu.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> qemu
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> qemu <span class="o">&amp;&amp;</span> ./configure --target-list<span class="o">=</span>riscv32-softmmu,riscv32-linux-user,riscv64-linux-user,riscv64-softmmu <span class="se">\
</span></span></span><span class="line"><span class="cl">               --enable-kvm --enable-sdl <span class="se">\
</span></span></span><span class="line"><span class="cl">               --prefix<span class="o">=</span>/home/user/program/riscv64-qemu
</span></span><span class="line"><span class="cl">make install -j <span class="k">$(</span>nproc<span class="k">)</span>
</span></span></code></pre></div><h3 id="准备-opensbi">准备 OpenSBI</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> workspace
</span></span><span class="line"><span class="cl">git clone https://github.com/riscv-software-src/opensbi.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> opensbi
</span></span><span class="line"><span class="cl">make <span class="nv">ARCH</span><span class="o">=</span>riscv <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-linux-gnu- <span class="nv">PLATFORM</span><span class="o">=</span>generic
</span></span></code></pre></div><h3 id="准备-linux-内核">准备 Linux 内核</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> workspace
</span></span><span class="line"><span class="cl">git clone https://github.com/torvalds/linux.git
</span></span><span class="line"><span class="cl">make <span class="nv">ARCH</span><span class="o">=</span>riscv <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-linux-gnu- defconfig
</span></span><span class="line"><span class="cl">make <span class="nv">ARCH</span><span class="o">=</span>riscv <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-linux-gnu- -j <span class="k">$(</span>nproc<span class="k">)</span>
</span></span></code></pre></div><h3 id="准备-busybox">准备 Busybox</h3>
<p>进入下载软件包，<a href="https://busybox.net/downloads/">https://busybox.net/downloads/</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
</span></span><span class="line"><span class="cl">tar -xvf busybox-1.36.1.tar.bz2
</span></span><span class="line"><span class="cl">mv busybox-1.36.1 busybox
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> busybox
</span></span></code></pre></div><p>配置编译选项</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">make <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-linux-gnu- menuconfig
</span></span></code></pre></div><p>选择静态库模式，设置路径：Settings -&gt; Build static binary (no shared libs)</p>
<p>

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

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

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>编译 Busybox</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">make <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-linux-gnu- -j <span class="k">$(</span>nproc<span class="k">)</span>
</span></span></code></pre></div><blockquote>
<p>如果需要频繁编译，也可以在 Menuconfig 中设置交叉编译器路径，这样就不需要每次都指定了。设置路径为：Settings -&gt; Build Options -&gt; Cross Compiler prefix。将其设置为 riscv64-unknown-linux-gnu-。</p>
</blockquote>
<p>安装 Busybox：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">make <span class="nv">CROSS_COMPILE</span><span class="o">=</span>riscv64-unknown-linux-gnu- install
</span></span></code></pre></div><blockquote>
<p>Busybox 默认安装在当前目录的_install 目录下，也可以在 Menuconfig 中设置安装目录，路径为：Settings -&gt; Build Options -&gt; Destination path for &lsquo;make install&rsquo;。</p>
</blockquote>
<p>查看安装目录</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">ls _install 
</span></span><span class="line"><span class="cl">bin  linuxrc  sbin  usr
</span></span></code></pre></div><p>制作根文件系统</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">qemu-img create -f raw rootfs.img 256M
</span></span><span class="line"><span class="cl">mkfs.ext4 rootfs.img
</span></span><span class="line"><span class="cl">mkdir rootfs
</span></span><span class="line"><span class="cl">sudo mount -o loop rootfs.img rootfs
</span></span><span class="line"><span class="cl">sudo cp -r _install/* rootfs
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">cd</span> rootfs
</span></span><span class="line"><span class="cl">sudo mkdir proc sys dev etc etc/init.d
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> etc
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> init.d
</span></span><span class="line"><span class="cl">sudo touch rcS
</span></span><span class="line"><span class="cl">sudo chmod +x rcS
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo vim rcS
</span></span></code></pre></div><p>写入以下内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="cp">#!/bin/sh  
</span></span></span><span class="line"><span class="cl">mount -t proc none /proc  
</span></span><span class="line"><span class="cl">mount -t sysfs none /sys  
</span></span><span class="line"><span class="cl">/sbin/mdev -s
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">sudo umount rootfs
</span></span></code></pre></div><p>qemu 启动内核：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="nv">RESTORE</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span> -en <span class="s1">&#39;\001\033[0m\002&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">YELLOW</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span> -en <span class="s1">&#39;\001\033[00;33m\002&#39;</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## Configuration</span>
</span></span><span class="line"><span class="cl"><span class="nv">vcpu</span><span class="o">=</span><span class="m">8</span>
</span></span><span class="line"><span class="cl"><span class="nv">memory</span><span class="o">=</span><span class="m">16</span>
</span></span><span class="line"><span class="cl"><span class="nv">drive</span><span class="o">=</span><span class="s2">&#34;/home/user/workspace/rootfs.img&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">kernel</span><span class="o">=</span><span class="s2">&#34; /home/user/workspace/linux-stable/arch/riscv/boot/Image&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">fw</span><span class="o">=</span><span class="s2">&#34;/home/user/workspace/opensbi/build/platform/generic/firmware/fw_jump.bin&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">ssh_port</span><span class="o">=</span><span class="m">12070</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">cmd</span><span class="o">=</span><span class="s2">&#34;/home/user/program/riscv64-qemu/bin/qemu-system-riscv64 \
</span></span></span><span class="line"><span class="cl"><span class="s2">  -nographic -machine virt \
</span></span></span><span class="line"><span class="cl"><span class="s2">  -smp &#34;</span><span class="nv">$vcpu</span><span class="s2">&#34; -m &#34;</span><span class="nv">$memory</span><span class="s2">&#34;G \
</span></span></span><span class="line"><span class="cl"><span class="s2">  -cpu rv64\
</span></span></span><span class="line"><span class="cl"><span class="s2">  -bios &#34;</span><span class="nv">$fw</span><span class="s2">&#34; \
</span></span></span><span class="line"><span class="cl"><span class="s2">  -kernel &#34;</span><span class="nv">$kernel</span><span class="s2">&#34; \
</span></span></span><span class="line"><span class="cl"><span class="s2">  -drive file=</span><span class="nv">$drive</span><span class="s2">,format=raw,id=hd0 \
</span></span></span><span class="line"><span class="cl"><span class="s2">  -device virtio-blk-device,drive=hd0 \
</span></span></span><span class="line"><span class="cl"><span class="s2">  -append &#34;</span><span class="nv">root</span><span class="o">=</span>/dev/vda <span class="nv">console</span><span class="o">=</span>ttyS0<span class="s2">&#34; &#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>:: Starting VM...<span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>:: Using following configuration<span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>vCPU Cores: <span class="s2">&#34;</span><span class="nv">$vcpu</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>Memory: <span class="s2">&#34;</span><span class="nv">$memory</span><span class="s2">&#34;</span>G<span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>Disk: <span class="s2">&#34;</span><span class="nv">$drive</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>SSH Port: <span class="s2">&#34;</span><span class="nv">$ssh_port</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>:: NOTE: Make sure ONLY ONE .qcow2 file is<span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>in the current directory<span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>:: Tip: Try setting DNS manually <span class="k">if</span> QEMU user network doesn<span class="se">\&#39;</span>t work well. <span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span>:: HOWTO -<span class="se">\&gt;</span> https://serverfault.com/a/810639 <span class="si">${</span><span class="nv">RESTORE</span><span class="si">}</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sleep <span class="m">2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">eval</span> <span class="nv">$cmd</span>
</span></span></code></pre></div><p>

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
]]></content:encoded>
    </item>
    <item>
      <title>uCore-实验第 0 章 - 实验环境搭建</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC0%E7%AB%A0-%E5%AE%9E%E9%AA%8C%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</link>
      <pubDate>Fri, 08 Sep 2023 10:46:20 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC0%E7%AB%A0-%E5%AE%9E%E9%AA%8C%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;本次实验是清华大学操作系统课程的课程实验，实验内容是基于 RISC-V 架构的 uCore 操作系统。本次实验的目的是搭建实验环境，为后续实验做准备。指导书参考&lt;a href=&#34;https://learningos.github.io/uCore-Tutorial-Guide-2023S/index.html&#34;&gt;uCore-Tutorial-Guide-2023S 文档&lt;/a&gt;。本系列文章内容主要是指导书的补充以及我在实验过程的一些理解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本章没有什么需要特别说明的，指导手册十分详细，按照指导手册的步骤一步步来就可以了。因为平时也在用 WSL2 开发，所以配置十分顺利，没有遇到什么问题。这篇文章就当占坑了，如果后续有什么需要补充的再来更新。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<blockquote>
<p>本次实验是清华大学操作系统课程的课程实验，实验内容是基于 RISC-V 架构的 uCore 操作系统。本次实验的目的是搭建实验环境，为后续实验做准备。指导书参考<a href="https://learningos.github.io/uCore-Tutorial-Guide-2023S/index.html">uCore-Tutorial-Guide-2023S 文档</a>。本系列文章内容主要是指导书的补充以及我在实验过程的一些理解。</p>
</blockquote>
<p>本章没有什么需要特别说明的，指导手册十分详细，按照指导手册的步骤一步步来就可以了。因为平时也在用 WSL2 开发，所以配置十分顺利，没有遇到什么问题。这篇文章就当占坑了，如果后续有什么需要补充的再来更新。</p>
]]></content:encoded>
    </item>
    <item>
      <title>uCore-实验第 1 章 - 应用程序与基本执行环境</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC1%E7%AB%A0-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E4%B8%8E%E5%9F%BA%E6%9C%AC%E6%89%A7%E8%A1%8C%E7%8E%AF%E5%A2%83/</link>
      <pubDate>Fri, 08 Sep 2023 10:45:14 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC1%E7%AB%A0-%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E4%B8%8E%E5%9F%BA%E6%9C%AC%E6%89%A7%E8%A1%8C%E7%8E%AF%E5%A2%83/</guid>
      <description>&lt;h1 id=&#34;了解系统调用&#34;&gt;了解系统调用&lt;/h1&gt;
&lt;p&gt;操作系统的系统调用（syscall）是操作系统提供给应用程序使用的一种接口。它允许应用程序通过向操作系统发送请求，来执行一些必须由操作系统来完成的任务，例如读取文件、创建进程、分配内存等。&lt;/p&gt;
&lt;p&gt;通俗地说，可以把操作系统看作一个巨大的服务员，而应用程序就像是顾客。应用程序不能直接访问硬件或执行特权操作，因为这样可能会导致系统不稳定或不安全。所以，应用程序需要通过系统调用来与操作系统进行交互，请求操作系统代表它完成某些任务。&lt;/p&gt;
&lt;p&gt;当应用程序需要操作系统执行特定的功能时，它会调用适当的系统调用函数，并传递参数给它。然后操作系统会接收到这个请求，并根据请求的类型和参数来执行相应的操作。完成后，操作系统会将执行结果返回给应用程序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在 RISC-V 架构中&lt;/strong&gt;，系统调用是通过使用特定的指令来实现的。具体来说，RISC-V 架构提供了一个称为 &lt;code&gt;ecall&lt;/code&gt;（environment call）的指令来触发系统调用。&lt;/p&gt;
&lt;p&gt;要使用 syscall，在 RISC-V 汇编代码中可以通过以下步骤来完成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将系统调用编号（syscall number）放入寄存器 a7 中，该编号对应于所需的系统调用功能。&lt;/li&gt;
&lt;li&gt;将系统调用所需的参数放入其他相应的寄存器中。例如，参数传递给文件读取系统调用可能需要将文件描述符放入 a0 寄存器，缓冲区地址放入 a1 寄存器，以及读取的字节数放入 a2 寄存器。&lt;/li&gt;
&lt;li&gt;执行 ecall 指令。这会触发操作系统处理当前运行的程序的系统调用请求。&lt;/li&gt;
&lt;li&gt;操作系统接收到系统调用请求后，根据寄存器 a7 中的系统调用编号和其他寄存器中的参数来执行相应的操作。&lt;/li&gt;
&lt;li&gt;当操作系统完成系统调用请求时，它将结果放入适当的寄存器中，通常是 a0 寄存器。&lt;/li&gt;
&lt;li&gt;程序继续执行，可以检查结果并进行后续的处理。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要注意的是，具体的系统调用编号以及参数的传递方式会根据操作系统的实现而有所不同。所以在编写 RISC-V 汇编代码时，需要参考操作系统的相关文档来了解具体的系统调用接口和参数传递方式。&lt;/p&gt;
&lt;h1 id=&#34;makr-run-之后发生了什么&#34;&gt;makr run 之后发生了什么？&lt;/h1&gt;
&lt;p&gt;当执行&lt;code&gt;make run&lt;/code&gt;命令后，以下是运行流程的概述：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;内核代码编译：执行&lt;code&gt;make run&lt;/code&gt;会触发 Makefile 中的相应规则，从而编译生成内核（kernel）二进制文件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;加载 kernel 并启动 QEMU：根据 QEMUOPTS 变量指定的参数，QEMU 加载生成的 kernel 二进制文件，并启动模拟器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;引导代码执行：在模拟器启动后，CPU 的通用寄存器被清零，程序计数器（PC）指向 0x1000 的位置，这里有硬件固化的一小段引导代码。该引导代码会迅速跳转到 0x80000000 处的 RustSBI（Rust Supervisor Binary Interface）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RustSBI 完成硬件初始化：RustSBI 是一个用于与操作系统进行交互的接口层。在跳转到 RustSBI 之后，它会完成必要的硬件初始化工作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行操作系统第一条指令：RustSBI 在完成硬件初始化后，会跳转到 kernel 二进制文件所在内存位置 0x80200000 处，并开始执行我们操作系统的第一条指令。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;综上所述，执行&lt;code&gt;make run&lt;/code&gt;命令会完成内核的编译和加载，启动 QEMU 虚拟机，并经过引导代码和 RustSBI 的处理，最终开始执行操作系统的第一条指令。&lt;/p&gt;
&lt;h1 id=&#34;了解链接脚本&#34;&gt;了解链接脚本&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# kernel.ld
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;BASE_ADDRESS = 0x80200000;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SECTIONS
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   . = BASE_ADDRESS;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   skernel = .;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   stext = .;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   .text : {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      *(.text.entry)   # 第一行代码
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      *(.text .text.*)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;kernelld-中的-base_address--0x80200000-指定了内核的加载地址这个地址哪来的&#34;&gt;kernel.ld 中的 &lt;code&gt;BASE_ADDRESS = 0x80200000&lt;/code&gt; 指定了内核的加载地址，这个地址哪来的？&lt;/h2&gt;
&lt;p&gt;以下内容摘自参考&lt;a href=&#34;https://rcore-os.cn/rCore-Tutorial-Book-v3/chapter1/3first-instruction-in-kernel1.html&#34;&gt;rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档&lt;/a&gt;：&lt;/p&gt;
&lt;p&gt;在 Qemu 模拟的 virt 硬件平台上，物理内存的起始物理地址为 &lt;code&gt;0x80000000&lt;/code&gt;，物理内存的默认大小为 128MiB，它可以通过 &lt;code&gt;-m&lt;/code&gt; 选项进行配置。如果使用默认配置的 128MiB 物理内存则对应的物理地址区间为 &lt;code&gt;[0x80000000,0x88000000)&lt;/code&gt; 。如果使用上面给出的命令启动 Qemu，那么在 Qemu 开始执行任何指令之前，首先把两个文件加载到 Qemu 的物理内存中：即作把作为 bootloader 的 rustsbi-qemu.bin 加载到物理内存以物理地址 &lt;code&gt;0x80000000&lt;/code&gt; 开头的区域上，同时把内核镜像 &lt;code&gt;os.bin&lt;/code&gt; 加载到以物理地址 &lt;code&gt;0x80200000&lt;/code&gt; 开头的区域上。&lt;/p&gt;
&lt;p&gt;为什么加载到这两个位置呢？这与 Qemu 模拟计算机加电启动后的运行流程有关。一般来说，计算机加电之后的启动流程可以分成若干个阶段，每个阶段均由一层软件或 固件 负责，每一层软件或固件的功能是进行它应当承担的初始化工作，并在此之后跳转到下一层软件或固件的入口地址，也就是将计算机的控制权移交给了下一层软件或固件。Qemu 模拟的启动流程则可以分为三个阶段：第一个阶段由固化在 Qemu 内的一小段汇编程序负责；第二个阶段由 bootloader 负责；第三个阶段则由内核镜像负责。&lt;/p&gt;
&lt;p&gt;第一阶段：将必要的文件载入到 Qemu 物理内存之后，Qemu CPU 的程序计数器（PC, Program Counter）会被初始化为 0x1000，因此 Qemu 实际执行的第一条指令位于物理地址 0x1000，接下来它将执行寥寥数条指令并跳转到物理地址 &lt;code&gt;0x80000000&lt;/code&gt; 对应的指令处并进入第二阶段。从后面的调试过程可以看出，该地址 &lt;code&gt;0x80000000&lt;/code&gt; 被固化在 Qemu 中，作为 Qemu 的使用者，我们在不触及 Qemu 源代码的情况下无法进行更改。&lt;/p&gt;
&lt;p&gt;第二阶段：由于 Qemu 的第一阶段固定跳转到 &lt;code&gt;0x80000000&lt;/code&gt;，我们需要将负责第二阶段的 bootloader rustsbi-qemu.bin 放在以物理地址 &lt;code&gt;0x80000000&lt;/code&gt; 开头的物理内存中，这样就能保证 &lt;code&gt;0x80000000&lt;/code&gt; 处正好保存 bootloader 的第一条指令。在这一阶段，bootloader 负责对计算机进行一些初始化工作，并跳转到下一阶段软件的入口，在 Qemu 上即可实现将计算机控制权移交给我们的内核镜像 os.bin。这里需要注意的是，对于不同的 bootloader 而言，下一阶段软件的入口不一定相同，而且获取这一信息的方式和时间点也不同：入口地址可能是一个预先约定好的固定的值，也有可能是在 bootloader 运行期间才动态获取到的值。我们选用的 RustSBI 则是将下一阶段的入口地址预先约定为固定的 0x80200000，在 RustSBI 的初始化工作完成之后，它会跳转到该地址并将计算机控制权移交给下一阶段的软件——也即我们的内核镜像。&lt;/p&gt;
&lt;p&gt;第三阶段：为了正确地和上一阶段的 RustSBI 对接，我们需要保证内核的第一条指令位于物理地址 &lt;code&gt;0x80200000&lt;/code&gt; 处。为此，我们需要将内核镜像预先加载到 Qemu 物理内存以地址 0x80200000 开头的区域上。一旦 CPU 开始执行内核的第一条指令，证明计算机的控制权已经被移交给我们的内核，也就达到了本节的目标。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以上过程是 QEMU 中的启动流程，真实计算机的加电启动流程大致如下：
第一阶段：加电后 CPU 的 PC 寄存器被设置为计算机内部只读存储器（ROM，Read-only Memory）的物理地址，随后 CPU 开始运行 ROM 内的软件。我们一般将该软件称为固件（Firmware），它的功能是对 CPU 进行一些初始化操作，将后续阶段的 bootloader 的代码、数据从硬盘载入到物理内存，最后跳转到适当的地址将计算机控制权转移给 bootloader。它大致对应于 Qemu 启动的第一阶段，即在物理地址 0x1000 处放置的若干条指令。可以看到 Qemu 上的固件非常简单，因为它并不需要负责将 bootloader 从硬盘加载到物理内存中，这个任务此前已经由 Qemu 自身完成了。
第二阶段：bootloader 同样完成一些 CPU 的初始化工作，将操作系统镜像从硬盘加载到物理内存中，最后跳转到适当地址将控制权转移给操作系统。可以看到一般情况下 bootloader 需要完成一些数据加载工作，这也就是它名字中 loader 的来源。它对应于 Qemu 启动的第二阶段。在 Qemu 中，我们使用的 RustSBI 功能较弱，它并没有能力完成加载的工作，内核镜像实际上是和 bootloader 一起在 Qemu 启动之前加载到物理内存中的。
第三阶段：控制权被转移给操作系统。由于篇幅所限后面我们就不再赘述了。
值得一提的是，为了让计算机的启动更加灵活，bootloader 目前可能非常复杂：它可能也分为多个阶段，并且能管理一些硬件资源，从复杂性上它已接近一个传统意义上的操作系统。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;终端是如何控制颜色的&#34;&gt;终端是如何控制颜色的？&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LOG_COLOR&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;RED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;GREEN&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;BLUE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;34&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;GRAY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;90&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;YELLOW&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;93&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#if defined(USE_LOG_ERROR)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define errorf(fmt, ...)                                               \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	do {                                                               \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;		int tid = threadid();                                          \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;		printf(&amp;#34;\x1b[%dm[%s %d]&amp;#34; fmt &amp;#34;\x1b[0m\n&amp;#34;, RED, &amp;#34;ERROR&amp;#34;, tid,   \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;		       ##__VA_ARGS__);                                         \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	} while (0)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ANSI 转义码是一种用于控制终端输出的特殊字符序列。它们由&lt;code&gt;\x1b&lt;/code&gt;（或&lt;code&gt;\033&lt;/code&gt;）开头，后面跟着一系列数字和分号组成。&lt;/p&gt;
&lt;p&gt;ANSI 转义码中的数字部分用于指定不同的控制操作，如设置文本颜色、背景颜色、光标位置等等。其中，用于设置颜色的转义码包括三个主要的部分：&lt;code&gt;\x1b[颜色代码m&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;具体来说，&lt;code&gt;\x1b[&lt;/code&gt;表示开始使用控制序列，接下来的数字代表不同的颜色代码，最后的&lt;code&gt;m&lt;/code&gt;表示结束控制序列。例如，&lt;code&gt;\x1b[31m&lt;/code&gt;表示将文本颜色设置为红色，而&lt;code&gt;\x1b[0m&lt;/code&gt;用于重置所有属性为默认值。&lt;/p&gt;
&lt;p&gt;当终端遇到这样的转义序列时，它会解析并执行相应的控制操作，从而实现对文本颜色、背景颜色和其他属性的控制。&lt;/p&gt;
&lt;p&gt;需要注意的是，不同的终端可能支持不同的 ANSI 转义码，并且不同操作系统也可能有不同的实现。因此，在编写使用 ANSI 转义码的代码时，建议先测试并确保其在目标终端上正常工作。&lt;/p&gt;
&lt;p&gt;更多详细解释可以参考文章：&lt;a href=&#34;https://www.jianshu.com/p/790fc612aaa5&#34;&gt;终端颜色控制 - 简书&lt;/a&gt;。&lt;/p&gt;
&lt;h1 id=&#34;应用程序输出字符会调用-sbi-服务sbi-中发生了什么&#34;&gt;应用程序输出字符会调用 SBI 服务，SBI 中发生了什么？&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;因为对 Rust 语言不熟悉，所以这里的分析是基于 C 语言的 OpenSBI 来分析的，他们的逻辑是一样的。如果有熟悉 Rust 的可以查看 &lt;a href=&#34;https://github.com/rustsbi/rustsbi/blob/main/src/instance.rs&#34;&gt;RustSBI 源码&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据指导书中的解释以及阅读代码，我们知道调用了 &lt;code&gt;printf&lt;/code&gt; 最终实际上是调用了 &lt;code&gt;sbi_call&lt;/code&gt;。那么 &lt;code&gt;sbi_call&lt;/code&gt; 是如何实现的呢？因为我是做驱动开发以及固件开发的，也经常需要使用 OpenSBI，所想多问一句，OpenSBI 是如何实现的呢？OpenSBI 是如何提供服务的呢？它是如何打印出字符的呢？&lt;/p&gt;
&lt;h2 id=&#34;内核中的-sbi-调用&#34;&gt;内核中的 SBI 调用&lt;/h2&gt;
&lt;p&gt;我们先看一下内核中的 &lt;code&gt;sbi_call&lt;/code&gt; 都做了写啥。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// uCore-Tutorial-Code-2023S/os/sbi.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_CONSOLE_PUTCHAR&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;console_putchar&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;sbi_call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SBI_CONSOLE_PUTCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// uCore-Tutorial-Code-2023S/os/sbi.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;inline&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_call&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;which&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 使用寄存器变量来保存参数值和系统调用编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;register&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;a0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 将 &amp;#39;arg0&amp;#39; 的值保存在寄存器 &amp;#39;a0&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;register&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a1&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;a1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 将 &amp;#39;arg1&amp;#39; 的值保存在寄存器 &amp;#39;a1&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;register&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a2&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;a2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;arg2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 将 &amp;#39;arg2&amp;#39; 的值保存在寄存器 &amp;#39;a2&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;register&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a7&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;a7&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;which&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 &amp;#39;which&amp;#39; 的值保存在寄存器 &amp;#39;a7&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 内联汇编代码使用 ecall 指令进行系统调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;volatile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s&#34;&gt;&amp;#34;ecall&amp;#34;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 使用 ecall 指令进行系统调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 在这段代码中，指令 &amp;#34;ecall&amp;#34; 的输入参数是寄存器 a0 a1 a2 和 a7，输出参数是寄存器 a0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 输出操作数：将返回值存储在变量 &amp;#39;a0&amp;#39; 中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 输入操作数：传递参数和系统调用编号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;memory&amp;#34;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;//  &amp;#34;memory&amp;#34; 标志告诉编译器，这条指令可能会修改内存中的数据，需要进行内存屏障操作来保证数据的正确性。 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 返回存储在变量 &amp;#39;a0&amp;#39; 中的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么 OpenSBI 如何提供服务？在&lt;code&gt;include/sbi/sbi_ecall.h&lt;/code&gt;这种定义了每个&lt;code&gt;ecall&lt;/code&gt;服务全局变量。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//include/sbi/sbi_ecall.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_base&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_legacy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_rfence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_ipi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_vendor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_hsm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_srst&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;lib/sbi/sbi_ecall.c&lt;/code&gt;中注册了所有的&lt;code&gt;ecall&lt;/code&gt;服务，并将其加到链表&lt;code&gt;ecall_exts_list&lt;/code&gt;中。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_exts_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_exts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_register_extension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_register_extension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EINVAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;sbi_list_for_each_entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ecall_exts_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;cm&#34;&gt;/* no overlap */&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EINVAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;SBI_INIT_LIST_HEAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nf&#34;&gt;sbi_list_add_tail&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ecall_exts_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * Iterate over list of given type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param pos the type * to use as a loop cursor.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param head the head for your list.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; * @param member the name of the list_struct within the struct.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define sbi_list_for_each_entry(pos, head, member) \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	for (pos = sbi_list_entry((head)-&amp;gt;next, typeof(*pos), member);	\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	     &amp;amp;pos-&amp;gt;member != (head); 	\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;	     pos = sbi_list_entry(pos-&amp;gt;member.next, typeof(*pos), member))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么服务 id 如何和相对应的服务绑定的呢？以&lt;code&gt;ecall_time&lt;/code&gt;为例，查看其结构体原型&lt;code&gt;struct sbi_ecall_extension&lt;/code&gt; ：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// include/sbi/sbi_ecall.h: 23
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_dlist&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;probe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;funcid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		       &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		       &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		       &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到有 &lt;code&gt;extid_start&lt;/code&gt;、&lt;code&gt;extid_end&lt;/code&gt; 和 &lt;code&gt;handle&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;目前 OpenSBI 逐步将每个服务的实现都放在了&lt;code&gt;lib/sbi&lt;/code&gt;单独文件中，以&lt;code&gt;ecall_time&lt;/code&gt;为例，其实现在&lt;code&gt;lib/sbi/sbi_ecall_time.c&lt;/code&gt;中。单独为其绑定回调处理函数&lt;code&gt;sbi_ecall_time_handler&lt;/code&gt;。但是还有很多服务的实现还是放在了&lt;code&gt;lib/sbi/sbi_ecall_legacy.c&lt;/code&gt;中，后续应该会逐步迁移。我们上文使用的&lt;code&gt;SBI_CONSOLE_PUTCHAR&lt;/code&gt;服务就是在这里实现的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// lib/sbi/sbi_ecall_legacy.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_extension&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecall_legacy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_start&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EXT_0_1_SET_TIMER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid_end&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EXT_0_1_SHUTDOWN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_ecall_legacy_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_legacy_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;funcid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_tlb_info&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;tlb_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;source_hart&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;current_hartid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;ulong&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hmask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SBI_EXT_0_1_SET_TIMER&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;sbi_timer_event_start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SBI_EXT_0_1_CONSOLE_PUTCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nf&#34;&gt;sbi_putc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SBI_EXT_0_1_CONSOLE_GETCHAR&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_getc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这就把 &lt;code&gt;id&lt;/code&gt; 与相应的服务函数绑定。一个&lt;code&gt;extid&lt;/code&gt;对应一个&lt;code&gt;handler&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;我们可以在找到&lt;code&gt;SBI_EXT_0_1_CONSOLE_PUTCHAR&lt;/code&gt;的值，是与 Linux 内核里定义的值是一致的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// include/sbi/sbi_ecall_interface.h
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* SBI Extension IDs */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define SBI_EXT_0_1_CONSOLE_PUTCHAR		0x1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ecall-服务调用流程&#34;&gt;ecall 服务调用流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;firmware/fw_base.S&lt;/code&gt; 中注册了 &lt;code&gt;Machine Mode&lt;/code&gt; 的 &lt;code&gt;trap handler&lt;/code&gt;，即 &lt;code&gt;sbi_trap_handler&lt;/code&gt;；&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;_start_warm:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Setup trap handler */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;la&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;a4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;_trap_handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;csrw&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;CSR_MTVEC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a4&lt;/span&gt;  &lt;span class=&#34;cm&#34;&gt;/* CSR_MTVEC = _trap_handler */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;_trap_handler:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_SAVE_AND_SETUP_SP_T0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_SAVE_MEPC_MSTATUS&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_CALL_C_ROUTINE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_RESTORE_MEPC_MSTATUS&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;TRAP_RESTORE_SP_T0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;mret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.macro&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;TRAP_CALL_C_ROUTINE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;cm&#34;&gt;/* Call C routine */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;add&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;a0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;sp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;call&lt;/span&gt;	&lt;span class=&#34;no&#34;&gt;sbi_trap_handler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;.endm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;lib/sbi/sbi_trap.c&lt;/code&gt; 中定义了 &lt;code&gt;sbi_trap_handler&lt;/code&gt;，处理各种 &lt;code&gt;mcause&lt;/code&gt;，比如 &lt;code&gt;Illegal Instructions&lt;/code&gt;，&lt;code&gt;Misaligned Load &amp;amp; Store&lt;/code&gt;, &lt;code&gt;Supervisor &amp;amp; Machine Ecall&lt;/code&gt; 等。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// lib/sbi/sbi_trap.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_trap_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mcause&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_ILLEGAL_INSTRUCTION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_illegal_insn_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mtval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_MISALIGNED_LOAD&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_misaligned_load_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mtval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtval2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtinst&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_MISALIGNED_STORE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_misaligned_store_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mtval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtval2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtinst&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_SUPERVISOR_ECALL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;CAUSE_MACHINE_ECALL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/* If the trap came from S or U mode, redirect it there */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;epc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mepc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cause&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mcause&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tval2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtval2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tinst&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mtinst&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;rc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_trap_redirect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;lib/sbi/sbi_ecall.c&lt;/code&gt; 中定义了处理 &lt;code&gt;ecall mcause&lt;/code&gt; 的 &lt;code&gt;sbi_ecall_handler&lt;/code&gt;，它遍历上面 &lt;code&gt;ecall_exts_list&lt;/code&gt; 中注册的各种 &lt;code&gt;ecall&lt;/code&gt; 服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;sbi_ecall_handler&lt;/code&gt; 根据 Linux 内核传递的 &lt;code&gt;ext (extension id)&lt;/code&gt; 找到链表中对应的 &lt;code&gt;ecall&lt;/code&gt; 服务，执行其中的 &lt;code&gt;handle&lt;/code&gt; 函数，该函数根据 &lt;code&gt;fid&lt;/code&gt; 执行具体的服务内容。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// lib/sbi/sbi_ecall.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_regs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;func_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sbi_trap_info&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 遍历所有 ecall 服务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sbi_ecall_find_extension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 如果找到了就执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;handle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;func_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;regs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;out_val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trap&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EXT_0_1_SET_TIMER&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;extension_id&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_EXT_0_1_SHUTDOWN&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;is_0_1_spec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SBI_ENOTSUPP&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以发现 &lt;code&gt;extension_id&lt;/code&gt; 就是 a7 寄存器，他和我们在 uCore OS 中定义的 &lt;code&gt;SBI_EXT_0_1_CONSOLE_PUTCHAR&lt;/code&gt; 是一致的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;程序的内存布局与编译流程&#34;&gt;程序的内存布局与编译流程&lt;/h1&gt;
&lt;h2 id=&#34;程序的内存布局&#34;&gt;程序的内存布局&lt;/h2&gt;
&lt;h1 id=&#34;ucore-的编译系统&#34;&gt;uCore 的编译系统&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;.PHONY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clean&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 设置伪目标clean、build和user，可以通过命令make来执行这些目标
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build_kernel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 默认目标为build_kernel，即执行build_kernel目标下的指令
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?=&lt;/span&gt; error
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量LOG，默认值是error
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;K&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; os
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;TOOLPREFIX&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; riscv64-unknown-elf-
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CC&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;gcc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;AS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;gcc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LD&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;ld
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;OBJCOPY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;objcopy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;OBJDUMP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;objdump
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; python3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;GDB&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;TOOLPREFIX&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;gdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; cp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MKDIR_P&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; mkdir -p
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; build
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;C_SRCS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;wildcard &lt;span class=&#34;nv&#34;&gt;$K&lt;/span&gt;/*.c&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量C_SRCS，使用wildcard函数匹配所有以.c为后缀的文件，并存储在$K目录下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;AS_SRCS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;wildcard &lt;span class=&#34;nv&#34;&gt;$K&lt;/span&gt;/*.S&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量AS_SRCS，使用wildcard函数匹配所有以.S为后缀的文件，并存储在$K目录下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;C_OBJS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addprefix &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addsuffix .o, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;basename &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;C_SRCS&lt;span class=&#34;k&#34;&gt;))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量C_OBJS，通过addprefix和addsuffix函数将$(C_SRCS)中的路径替换为$(BUILDDIR)，并将后缀修改为.o
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;AS_OBJS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addprefix &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addsuffix .o, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;basename &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;AS_SRCS&lt;span class=&#34;k&#34;&gt;))))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量AS_OBJS，通过addprefix和addsuffix函数将$(AS_SRCS)中的路径替换为$(BUILDDIR)，并将后缀修改为.o
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;OBJS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;C_OBJS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;AS_OBJS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量OBJS，其值为$(C_OBJS)和$(AS_OBJS)的组合
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;HEADER_DEP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;addsuffix .d, &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;basename &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;C_OBJS&lt;span class=&#34;k&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量HEADER_DEP，通过addsuffix函数将$(C_OBJS)中的后缀修改为.d
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;-include&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;HEADER_DEP&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 包含$(HEADER_DEP)中的.d文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; -Wall -Werror -O -fno-omit-frame-pointer -ggdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量CFLAGS，并赋值为-Wall -Werror -O -fno-omit-frame-pointer -ggdb
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -MD
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将-MD选项追加到CFLAGS变量中，用于自动生成依赖关系文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -mcmodel&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;medany
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将-mcmodel=medany选项追加到CFLAGS变量中，用于指定内存模型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -ffreestanding -fno-common -nostdlib -mno-relax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将-ffreestanding -fno-common -nostdlib -mno-relax选项追加到CFLAGS变量中，用于编译无操作系统环境下的程序
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -I&lt;span class=&#34;nv&#34;&gt;$K&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将-I$K选项追加到CFLAGS变量中，用于指定头文件搜索路径为$K目录下
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;shell &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -fno-stack-protector -E -x c /dev/null &amp;gt;/dev/null 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; -fno-stack-protector&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 将$(CC) -fno-stack-protector -E -x c /dev/null &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&amp;amp; echo -fno-stack-protector命令执行结果追加到CFLAGS变量中，用于禁用栈保护机制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;error)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_ERROR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;warn)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_WARN
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;info)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_INFO
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;debug)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_DEBUG
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;trace)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -D LOG_LEVEL_TRACE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 根据$(LOG)变量的值，向CFLAGS变量追加相应的预处理器选项，相当于添加了一个宏定义，log.h中的LOG_LEVEL_ERROR等宏定义会根据这个宏定义来决定是否生效
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Disable PIE when possible (for Ubuntu 16.10 toolchain)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;ifneq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;shell&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;CC&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -&lt;span class=&#34;nv&#34;&gt;dumpspecs&lt;/span&gt; 2&amp;gt;/&lt;span class=&#34;nv&#34;&gt;dev&lt;/span&gt;/&lt;span class=&#34;nv&#34;&gt;null&lt;/span&gt; | &lt;span class=&#34;nv&#34;&gt;grep&lt;/span&gt; -&lt;span class=&#34;nv&#34;&gt;e&lt;/span&gt; &amp;#39;[^&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;]&lt;span class=&#34;nv&#34;&gt;no&lt;/span&gt;-&lt;span class=&#34;nv&#34;&gt;pie&lt;/span&gt;&amp;#39;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -fno-pie -no-pie
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;ifneq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;shell&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;CC&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -&lt;span class=&#34;nv&#34;&gt;dumpspecs&lt;/span&gt; 2&amp;gt;/&lt;span class=&#34;nv&#34;&gt;dev&lt;/span&gt;/&lt;span class=&#34;nv&#34;&gt;null&lt;/span&gt; | &lt;span class=&#34;nv&#34;&gt;grep&lt;/span&gt; -&lt;span class=&#34;nv&#34;&gt;e&lt;/span&gt; &amp;#39;[^&lt;span class=&#34;nv&#34;&gt;f&lt;/span&gt;]&lt;span class=&#34;nv&#34;&gt;nopie&lt;/span&gt;&amp;#39;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; -fno-pie -nopie
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 根据系统环境判断是否支持PIE（位置无关执行）选项，并根据情况向CFLAGS变量追加相应的选项
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;LDFLAGS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; -z max-page-size&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4096&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个变量LDFLAGS，并赋值为-z max-page-size=4096
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;$(AS_OBJS)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/$&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; : $&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @mkdir -p &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;@D&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -c $&amp;lt; -o &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 规则：生成$(AS_OBJS)目标所需的依赖文件$(BUILDDIR)/$K/%.o，依赖于$K/%.S，并通过$(CC)命令编译生成目标文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;$(C_OBJS)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/$&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;o&lt;/span&gt; : $&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/$&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @mkdir -p &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;@D&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -c $&amp;lt; -o &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 规则：生成$(C_OBJS)目标所需的依赖文件$(BUILDDIR)/$K/%.o，依赖于$K/%.c和$(BUILDDIR)/$K/%.d，并通过$(CC)命令编译生成目标文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;$(HEADER_DEP)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/$&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;d&lt;/span&gt; : $&lt;span class=&#34;n&#34;&gt;K&lt;/span&gt;/%.&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @mkdir -p &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;@D&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @set -e&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; rm -f &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;CC&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -MM $&amp;lt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;INCLUDEFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &amp;gt; &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;.&lt;span class=&#34;nv&#34;&gt;$$$$&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;s,\($*\)\.o[ :]*,\1.o $@ : ,g&amp;#39;&lt;/span&gt; &amp;lt; &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;.&lt;span class=&#34;nv&#34;&gt;$$$$&lt;/span&gt; &amp;gt; &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        rm -f &lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;.&lt;span class=&#34;nv&#34;&gt;$$$$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 规则：生成$(HEADER_DEP)目标所需的依赖文件$(BUILDDIR)/$K/%.d，依赖于$K/%.c，并通过$(CC)命令生成依赖关系文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;/&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义一个目标build，其依赖于build/kernel
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;build/kernel&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;OBJS&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;LD&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;LDFLAGS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -T os/kernel.ld -o &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;OBJS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;OBJDUMP&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -S &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel &amp;gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel.asm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;OBJDUMP&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -t &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sed &lt;span class=&#34;s1&#34;&gt;&amp;#39;1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d&amp;#39;&lt;/span&gt; &amp;gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;/kernel.sym
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    @echo &lt;span class=&#34;s1&#34;&gt;&amp;#39;Build kernel done&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 规则：生成build/kernel目标，依赖于$(OBJS)，通过$(LD)命令连接生成kernel，并通过$(OBJDUMP)命令生成汇编文件和符号表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;clean&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    rm -rf &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BUILDDIR&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# BOARD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;BOARD&lt;/span&gt;		&lt;span class=&#34;o&#34;&gt;?=&lt;/span&gt; qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SBI&lt;/span&gt;			&lt;span class=&#34;o&#34;&gt;?=&lt;/span&gt; rustsbi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;BOOTLOADER&lt;/span&gt;	&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; ./bootloader/rustsbi-qemu.bin
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;QEMU&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; qemu-system-riscv64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;QEMUOPTS&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	-nographic &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	-machine virt &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	-bios &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;BOOTLOADER&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	-kernel build/kernel	&lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;/&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMU&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMUOPTS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# QEMU&amp;#39;s gdb stub command line changed in 0.11
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;QEMUGDB&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;shell &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMU&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -help &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep -q &lt;span class=&#34;s1&#34;&gt;&amp;#39;^-gdb&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;then&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-gdb tcp::15234&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-s -p 15234&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 启动QEMU并通过GDB调试，此时QEMu会进入后台运行，并暂停执行，等待GDB连接
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 连接的GDB端口为15234
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;debug&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;/&lt;span class=&#34;n&#34;&gt;kernel&lt;/span&gt; .&lt;span class=&#34;n&#34;&gt;gdbinit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMU&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMUOPTS&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; -S &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;QEMUGDB&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	sleep &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;GDB&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译、运行 uCore 的一些常用命令有如下一些，涉及了后续章节中引入的测试用例中的命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make run
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make debug
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 编译测试用例的前四章&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make user &lt;span class=&#34;nv&#34;&gt;CHAPTER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 编译测试用例的第四章&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make user &lt;span class=&#34;nv&#34;&gt;CHAPTER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4_only &lt;span class=&#34;nv&#34;&gt;LOG&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;trace
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 只运行测试用例的第四章&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;CHAPTER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;4_only    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;附录&#34;&gt;附录&lt;/h1&gt;
&lt;p&gt;makefile 和 qemu&lt;/p&gt;
&lt;p&gt;AS = $(TOOLPREFIX)gas  &amp;gt; AS = $(TOOLPREFIX)as&lt;/p&gt;
&lt;h1 id=&#34;参考资料&#34;&gt;参考资料&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.jianshu.com/p/790fc612aaa5&#34;&gt;终端颜色控制 - 简书&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <content:encoded><![CDATA[<h1 id="了解系统调用">了解系统调用</h1>
<p>操作系统的系统调用（syscall）是操作系统提供给应用程序使用的一种接口。它允许应用程序通过向操作系统发送请求，来执行一些必须由操作系统来完成的任务，例如读取文件、创建进程、分配内存等。</p>
<p>通俗地说，可以把操作系统看作一个巨大的服务员，而应用程序就像是顾客。应用程序不能直接访问硬件或执行特权操作，因为这样可能会导致系统不稳定或不安全。所以，应用程序需要通过系统调用来与操作系统进行交互，请求操作系统代表它完成某些任务。</p>
<p>当应用程序需要操作系统执行特定的功能时，它会调用适当的系统调用函数，并传递参数给它。然后操作系统会接收到这个请求，并根据请求的类型和参数来执行相应的操作。完成后，操作系统会将执行结果返回给应用程序。</p>
<p><strong>在 RISC-V 架构中</strong>，系统调用是通过使用特定的指令来实现的。具体来说，RISC-V 架构提供了一个称为 <code>ecall</code>（environment call）的指令来触发系统调用。</p>
<p>要使用 syscall，在 RISC-V 汇编代码中可以通过以下步骤来完成：</p>
<ol>
<li>将系统调用编号（syscall number）放入寄存器 a7 中，该编号对应于所需的系统调用功能。</li>
<li>将系统调用所需的参数放入其他相应的寄存器中。例如，参数传递给文件读取系统调用可能需要将文件描述符放入 a0 寄存器，缓冲区地址放入 a1 寄存器，以及读取的字节数放入 a2 寄存器。</li>
<li>执行 ecall 指令。这会触发操作系统处理当前运行的程序的系统调用请求。</li>
<li>操作系统接收到系统调用请求后，根据寄存器 a7 中的系统调用编号和其他寄存器中的参数来执行相应的操作。</li>
<li>当操作系统完成系统调用请求时，它将结果放入适当的寄存器中，通常是 a0 寄存器。</li>
<li>程序继续执行，可以检查结果并进行后续的处理。</li>
</ol>
<p>需要注意的是，具体的系统调用编号以及参数的传递方式会根据操作系统的实现而有所不同。所以在编写 RISC-V 汇编代码时，需要参考操作系统的相关文档来了解具体的系统调用接口和参数传递方式。</p>
<h1 id="makr-run-之后发生了什么">makr run 之后发生了什么？</h1>
<p>当执行<code>make run</code>命令后，以下是运行流程的概述：</p>
<ol>
<li>
<p>内核代码编译：执行<code>make run</code>会触发 Makefile 中的相应规则，从而编译生成内核（kernel）二进制文件。</p>
</li>
<li>
<p>加载 kernel 并启动 QEMU：根据 QEMUOPTS 变量指定的参数，QEMU 加载生成的 kernel 二进制文件，并启动模拟器。</p>
</li>
<li>
<p>引导代码执行：在模拟器启动后，CPU 的通用寄存器被清零，程序计数器（PC）指向 0x1000 的位置，这里有硬件固化的一小段引导代码。该引导代码会迅速跳转到 0x80000000 处的 RustSBI（Rust Supervisor Binary Interface）。</p>
</li>
<li>
<p>RustSBI 完成硬件初始化：RustSBI 是一个用于与操作系统进行交互的接口层。在跳转到 RustSBI 之后，它会完成必要的硬件初始化工作。</p>
</li>
<li>
<p>执行操作系统第一条指令：RustSBI 在完成硬件初始化后，会跳转到 kernel 二进制文件所在内存位置 0x80200000 处，并开始执行我们操作系统的第一条指令。</p>
</li>
</ol>
<p>综上所述，执行<code>make run</code>命令会完成内核的编译和加载，启动 QEMU 虚拟机，并经过引导代码和 RustSBI 的处理，最终开始执行操作系统的第一条指令。</p>
<h1 id="了解链接脚本">了解链接脚本</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># kernel.ld
</span></span><span class="line"><span class="cl">BASE_ADDRESS = 0x80200000;
</span></span><span class="line"><span class="cl">SECTIONS
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">   . = BASE_ADDRESS;
</span></span><span class="line"><span class="cl">   skernel = .;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   stext = .;
</span></span><span class="line"><span class="cl">   .text : {
</span></span><span class="line"><span class="cl">      *(.text.entry)   # 第一行代码
</span></span><span class="line"><span class="cl">      *(.text .text.*)
</span></span><span class="line"><span class="cl">   }
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   ...
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><h2 id="kernelld-中的-base_address--0x80200000-指定了内核的加载地址这个地址哪来的">kernel.ld 中的 <code>BASE_ADDRESS = 0x80200000</code> 指定了内核的加载地址，这个地址哪来的？</h2>
<p>以下内容摘自参考<a href="https://rcore-os.cn/rCore-Tutorial-Book-v3/chapter1/3first-instruction-in-kernel1.html">rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档</a>：</p>
<p>在 Qemu 模拟的 virt 硬件平台上，物理内存的起始物理地址为 <code>0x80000000</code>，物理内存的默认大小为 128MiB，它可以通过 <code>-m</code> 选项进行配置。如果使用默认配置的 128MiB 物理内存则对应的物理地址区间为 <code>[0x80000000,0x88000000)</code> 。如果使用上面给出的命令启动 Qemu，那么在 Qemu 开始执行任何指令之前，首先把两个文件加载到 Qemu 的物理内存中：即作把作为 bootloader 的 rustsbi-qemu.bin 加载到物理内存以物理地址 <code>0x80000000</code> 开头的区域上，同时把内核镜像 <code>os.bin</code> 加载到以物理地址 <code>0x80200000</code> 开头的区域上。</p>
<p>为什么加载到这两个位置呢？这与 Qemu 模拟计算机加电启动后的运行流程有关。一般来说，计算机加电之后的启动流程可以分成若干个阶段，每个阶段均由一层软件或 固件 负责，每一层软件或固件的功能是进行它应当承担的初始化工作，并在此之后跳转到下一层软件或固件的入口地址，也就是将计算机的控制权移交给了下一层软件或固件。Qemu 模拟的启动流程则可以分为三个阶段：第一个阶段由固化在 Qemu 内的一小段汇编程序负责；第二个阶段由 bootloader 负责；第三个阶段则由内核镜像负责。</p>
<p>第一阶段：将必要的文件载入到 Qemu 物理内存之后，Qemu CPU 的程序计数器（PC, Program Counter）会被初始化为 0x1000，因此 Qemu 实际执行的第一条指令位于物理地址 0x1000，接下来它将执行寥寥数条指令并跳转到物理地址 <code>0x80000000</code> 对应的指令处并进入第二阶段。从后面的调试过程可以看出，该地址 <code>0x80000000</code> 被固化在 Qemu 中，作为 Qemu 的使用者，我们在不触及 Qemu 源代码的情况下无法进行更改。</p>
<p>第二阶段：由于 Qemu 的第一阶段固定跳转到 <code>0x80000000</code>，我们需要将负责第二阶段的 bootloader rustsbi-qemu.bin 放在以物理地址 <code>0x80000000</code> 开头的物理内存中，这样就能保证 <code>0x80000000</code> 处正好保存 bootloader 的第一条指令。在这一阶段，bootloader 负责对计算机进行一些初始化工作，并跳转到下一阶段软件的入口，在 Qemu 上即可实现将计算机控制权移交给我们的内核镜像 os.bin。这里需要注意的是，对于不同的 bootloader 而言，下一阶段软件的入口不一定相同，而且获取这一信息的方式和时间点也不同：入口地址可能是一个预先约定好的固定的值，也有可能是在 bootloader 运行期间才动态获取到的值。我们选用的 RustSBI 则是将下一阶段的入口地址预先约定为固定的 0x80200000，在 RustSBI 的初始化工作完成之后，它会跳转到该地址并将计算机控制权移交给下一阶段的软件——也即我们的内核镜像。</p>
<p>第三阶段：为了正确地和上一阶段的 RustSBI 对接，我们需要保证内核的第一条指令位于物理地址 <code>0x80200000</code> 处。为此，我们需要将内核镜像预先加载到 Qemu 物理内存以地址 0x80200000 开头的区域上。一旦 CPU 开始执行内核的第一条指令，证明计算机的控制权已经被移交给我们的内核，也就达到了本节的目标。</p>
<blockquote>
<p>以上过程是 QEMU 中的启动流程，真实计算机的加电启动流程大致如下：
第一阶段：加电后 CPU 的 PC 寄存器被设置为计算机内部只读存储器（ROM，Read-only Memory）的物理地址，随后 CPU 开始运行 ROM 内的软件。我们一般将该软件称为固件（Firmware），它的功能是对 CPU 进行一些初始化操作，将后续阶段的 bootloader 的代码、数据从硬盘载入到物理内存，最后跳转到适当的地址将计算机控制权转移给 bootloader。它大致对应于 Qemu 启动的第一阶段，即在物理地址 0x1000 处放置的若干条指令。可以看到 Qemu 上的固件非常简单，因为它并不需要负责将 bootloader 从硬盘加载到物理内存中，这个任务此前已经由 Qemu 自身完成了。
第二阶段：bootloader 同样完成一些 CPU 的初始化工作，将操作系统镜像从硬盘加载到物理内存中，最后跳转到适当地址将控制权转移给操作系统。可以看到一般情况下 bootloader 需要完成一些数据加载工作，这也就是它名字中 loader 的来源。它对应于 Qemu 启动的第二阶段。在 Qemu 中，我们使用的 RustSBI 功能较弱，它并没有能力完成加载的工作，内核镜像实际上是和 bootloader 一起在 Qemu 启动之前加载到物理内存中的。
第三阶段：控制权被转移给操作系统。由于篇幅所限后面我们就不再赘述了。
值得一提的是，为了让计算机的启动更加灵活，bootloader 目前可能非常复杂：它可能也分为多个阶段，并且能管理一些硬件资源，从复杂性上它已接近一个传统意义上的操作系统。</p>
</blockquote>
<h1 id="终端是如何控制颜色的">终端是如何控制颜色的？</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="k">enum</span> <span class="n">LOG_COLOR</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">RED</span> <span class="o">=</span> <span class="mi">31</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">GREEN</span> <span class="o">=</span> <span class="mi">32</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">BLUE</span> <span class="o">=</span> <span class="mi">34</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">GRAY</span> <span class="o">=</span> <span class="mi">90</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="n">YELLOW</span> <span class="o">=</span> <span class="mi">93</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#if defined(USE_LOG_ERROR)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define errorf(fmt, ...)                                               \
</span></span></span><span class="line"><span class="cl"><span class="cp">	do {                                                               \
</span></span></span><span class="line"><span class="cl"><span class="cp">		int tid = threadid();                                          \
</span></span></span><span class="line"><span class="cl"><span class="cp">		printf(&#34;\x1b[%dm[%s %d]&#34; fmt &#34;\x1b[0m\n&#34;, RED, &#34;ERROR&#34;, tid,   \
</span></span></span><span class="line"><span class="cl"><span class="cp">		       ##__VA_ARGS__);                                         \
</span></span></span><span class="line"><span class="cl"><span class="cp">	} while (0)
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span></code></pre></div><p>ANSI 转义码是一种用于控制终端输出的特殊字符序列。它们由<code>\x1b</code>（或<code>\033</code>）开头，后面跟着一系列数字和分号组成。</p>
<p>ANSI 转义码中的数字部分用于指定不同的控制操作，如设置文本颜色、背景颜色、光标位置等等。其中，用于设置颜色的转义码包括三个主要的部分：<code>\x1b[颜色代码m</code>。</p>
<p>具体来说，<code>\x1b[</code>表示开始使用控制序列，接下来的数字代表不同的颜色代码，最后的<code>m</code>表示结束控制序列。例如，<code>\x1b[31m</code>表示将文本颜色设置为红色，而<code>\x1b[0m</code>用于重置所有属性为默认值。</p>
<p>当终端遇到这样的转义序列时，它会解析并执行相应的控制操作，从而实现对文本颜色、背景颜色和其他属性的控制。</p>
<p>需要注意的是，不同的终端可能支持不同的 ANSI 转义码，并且不同操作系统也可能有不同的实现。因此，在编写使用 ANSI 转义码的代码时，建议先测试并确保其在目标终端上正常工作。</p>
<p>更多详细解释可以参考文章：<a href="https://www.jianshu.com/p/790fc612aaa5">终端颜色控制 - 简书</a>。</p>
<h1 id="应用程序输出字符会调用-sbi-服务sbi-中发生了什么">应用程序输出字符会调用 SBI 服务，SBI 中发生了什么？</h1>
<blockquote>
<p>因为对 Rust 语言不熟悉，所以这里的分析是基于 C 语言的 OpenSBI 来分析的，他们的逻辑是一样的。如果有熟悉 Rust 的可以查看 <a href="https://github.com/rustsbi/rustsbi/blob/main/src/instance.rs">RustSBI 源码</a></p>
</blockquote>
<p>根据指导书中的解释以及阅读代码，我们知道调用了 <code>printf</code> 最终实际上是调用了 <code>sbi_call</code>。那么 <code>sbi_call</code> 是如何实现的呢？因为我是做驱动开发以及固件开发的，也经常需要使用 OpenSBI，所想多问一句，OpenSBI 是如何实现的呢？OpenSBI 是如何提供服务的呢？它是如何打印出字符的呢？</p>
<h2 id="内核中的-sbi-调用">内核中的 SBI 调用</h2>
<p>我们先看一下内核中的 <code>sbi_call</code> 都做了写啥。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// uCore-Tutorial-Code-2023S/os/sbi.c
</span></span></span><span class="line"><span class="cl"><span class="k">const</span> <span class="n">uint64</span> <span class="n">SBI_CONSOLE_PUTCHAR</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">console_putchar</span><span class="p">(</span><span class="kt">int</span> <span class="n">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nf">sbi_call</span><span class="p">(</span><span class="n">SBI_CONSOLE_PUTCHAR</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// uCore-Tutorial-Code-2023S/os/sbi.c
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="kr">inline</span> <span class="nf">sbi_call</span><span class="p">(</span><span class="n">uint64</span> <span class="n">which</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">arg0</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">arg1</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">arg2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 使用寄存器变量来保存参数值和系统调用编号
</span></span></span><span class="line"><span class="cl">    <span class="k">register</span> <span class="n">uint64</span> <span class="n">a0</span> <span class="k">asm</span><span class="p">(</span><span class="s">&#34;a0&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">arg0</span><span class="p">;</span>  <span class="c1">// 将 &#39;arg0&#39; 的值保存在寄存器 &#39;a0&#39; 中
</span></span></span><span class="line"><span class="cl">    <span class="k">register</span> <span class="n">uint64</span> <span class="n">a1</span> <span class="k">asm</span><span class="p">(</span><span class="s">&#34;a1&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">arg1</span><span class="p">;</span>  <span class="c1">// 将 &#39;arg1&#39; 的值保存在寄存器 &#39;a1&#39; 中
</span></span></span><span class="line"><span class="cl">    <span class="k">register</span> <span class="n">uint64</span> <span class="n">a2</span> <span class="k">asm</span><span class="p">(</span><span class="s">&#34;a2&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">arg2</span><span class="p">;</span>  <span class="c1">// 将 &#39;arg2&#39; 的值保存在寄存器 &#39;a2&#39; 中
</span></span></span><span class="line"><span class="cl">    <span class="k">register</span> <span class="n">uint64</span> <span class="n">a7</span> <span class="k">asm</span><span class="p">(</span><span class="s">&#34;a7&#34;</span><span class="p">)</span> <span class="o">=</span> <span class="n">which</span><span class="p">;</span> <span class="c1">// 将 &#39;which&#39; 的值保存在寄存器 &#39;a7&#39; 中
</span></span></span><span class="line"><span class="cl">    <span class="c1">// 内联汇编代码使用 ecall 指令进行系统调用
</span></span></span><span class="line"><span class="cl">    <span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;ecall&#34;</span>  <span class="c1">// 使用 ecall 指令进行系统调用
</span></span></span><span class="line"><span class="cl">        <span class="c1">// 在这段代码中，指令 &#34;ecall&#34; 的输入参数是寄存器 a0 a1 a2 和 a7，输出参数是寄存器 a0
</span></span></span><span class="line"><span class="cl">        <span class="o">:</span> <span class="s">&#34;=r&#34;</span><span class="p">(</span><span class="n">a0</span><span class="p">)</span>  <span class="c1">// 输出操作数：将返回值存储在变量 &#39;a0&#39; 中
</span></span></span><span class="line"><span class="cl">        <span class="o">:</span> <span class="s">&#34;r&#34;</span><span class="p">(</span><span class="n">a0</span><span class="p">),</span> <span class="s">&#34;r&#34;</span><span class="p">(</span><span class="n">a1</span><span class="p">),</span> <span class="s">&#34;r&#34;</span><span class="p">(</span><span class="n">a2</span><span class="p">),</span> <span class="s">&#34;r&#34;</span><span class="p">(</span><span class="n">a7</span><span class="p">)</span>  <span class="c1">// 输入操作数：传递参数和系统调用编号
</span></span></span><span class="line"><span class="cl">        <span class="o">:</span> <span class="s">&#34;memory&#34;</span>  <span class="c1">//  &#34;memory&#34; 标志告诉编译器，这条指令可能会修改内存中的数据，需要进行内存屏障操作来保证数据的正确性。 
</span></span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a0</span><span class="p">;</span>  <span class="c1">// 返回存储在变量 &#39;a0&#39; 中的值
</span></span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>那么 OpenSBI 如何提供服务？在<code>include/sbi/sbi_ecall.h</code>这种定义了每个<code>ecall</code>服务全局变量。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">//include/sbi/sbi_ecall.h
</span></span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_base</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_legacy</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_time</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_rfence</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_ipi</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_vendor</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_hsm</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">extern</span> <span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_srst</span><span class="p">;</span>
</span></span></code></pre></div><p>在<code>lib/sbi/sbi_ecall.c</code>中注册了所有的<code>ecall</code>服务，并将其加到链表<code>ecall_exts_list</code>中。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">sbi_ecall_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">ret</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="o">*</span><span class="n">ext</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">i</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">sbi_ecall_exts_size</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">ext</span> <span class="o">=</span> <span class="n">sbi_ecall_exts</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">		<span class="n">ret</span> <span class="o">=</span> <span class="nf">sbi_ecall_register_extension</span><span class="p">(</span><span class="n">ext</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">sbi_ecall_register_extension</span><span class="p">(</span><span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="o">*</span><span class="n">ext</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="o">*</span><span class="n">t</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ext</span> <span class="o">||</span> <span class="p">(</span><span class="n">ext</span><span class="o">-&gt;</span><span class="n">extid_end</span> <span class="o">&lt;</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="n">extid_start</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span><span class="n">ext</span><span class="o">-&gt;</span><span class="n">handle</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="n">SBI_EINVAL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nf">sbi_list_for_each_entry</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ecall_exts_list</span><span class="p">,</span> <span class="n">head</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">start</span> <span class="o">=</span> <span class="n">t</span><span class="o">-&gt;</span><span class="n">extid_start</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">end</span> <span class="o">=</span> <span class="n">t</span><span class="o">-&gt;</span><span class="n">extid_end</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="p">(</span><span class="n">end</span> <span class="o">&lt;</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="n">extid_start</span> <span class="o">||</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="n">extid_end</span> <span class="o">&lt;</span> <span class="n">start</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="cm">/* no overlap */</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="k">else</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="n">SBI_EINVAL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nf">SBI_INIT_LIST_HEAD</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ext</span><span class="o">-&gt;</span><span class="n">head</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="nf">sbi_list_add_tail</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ext</span><span class="o">-&gt;</span><span class="n">head</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ecall_exts_list</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * Iterate over list of given type
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param pos the type * to use as a loop cursor.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param head the head for your list.
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param member the name of the list_struct within the struct.
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define sbi_list_for_each_entry(pos, head, member) \
</span></span></span><span class="line"><span class="cl"><span class="cp">	for (pos = sbi_list_entry((head)-&gt;next, typeof(*pos), member);	\
</span></span></span><span class="line"><span class="cl"><span class="cp">	     &amp;pos-&gt;member != (head); 	\
</span></span></span><span class="line"><span class="cl"><span class="cp">	     pos = sbi_list_entry(pos-&gt;member.next, typeof(*pos), member))
</span></span></span></code></pre></div><p>那么服务 id 如何和相对应的服务绑定的呢？以<code>ecall_time</code>为例，查看其结构体原型<code>struct sbi_ecall_extension</code> ：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// include/sbi/sbi_ecall.h: 23
</span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">struct</span> <span class="n">sbi_dlist</span> <span class="n">head</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid_start</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid_end</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="p">(</span><span class="o">*</span> <span class="n">probe</span><span class="p">)(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">out_val</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="p">(</span><span class="o">*</span> <span class="n">handle</span><span class="p">)(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">funcid</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		       <span class="k">const</span> <span class="k">struct</span> <span class="n">sbi_trap_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		       <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">out_val</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		       <span class="k">struct</span> <span class="n">sbi_trap_info</span> <span class="o">*</span><span class="n">out_trap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>可以看到有 <code>extid_start</code>、<code>extid_end</code> 和 <code>handle</code>。</p>
<p>目前 OpenSBI 逐步将每个服务的实现都放在了<code>lib/sbi</code>单独文件中，以<code>ecall_time</code>为例，其实现在<code>lib/sbi/sbi_ecall_time.c</code>中。单独为其绑定回调处理函数<code>sbi_ecall_time_handler</code>。但是还有很多服务的实现还是放在了<code>lib/sbi/sbi_ecall_legacy.c</code>中，后续应该会逐步迁移。我们上文使用的<code>SBI_CONSOLE_PUTCHAR</code>服务就是在这里实现的。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// lib/sbi/sbi_ecall_legacy.c
</span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">sbi_ecall_extension</span> <span class="n">ecall_legacy</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="n">extid_start</span> <span class="o">=</span> <span class="n">SBI_EXT_0_1_SET_TIMER</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="n">extid_end</span> <span class="o">=</span> <span class="n">SBI_EXT_0_1_SHUTDOWN</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">.</span><span class="n">handle</span> <span class="o">=</span> <span class="n">sbi_ecall_legacy_handler</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">sbi_ecall_legacy_handler</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extid</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">funcid</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				    <span class="k">const</span> <span class="k">struct</span> <span class="n">sbi_trap_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="o">*</span><span class="n">out_val</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">				    <span class="k">struct</span> <span class="n">sbi_trap_info</span> <span class="o">*</span><span class="n">out_trap</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">struct</span> <span class="n">sbi_tlb_info</span> <span class="n">tlb_info</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="n">u32</span> <span class="n">source_hart</span> <span class="o">=</span> <span class="nf">current_hartid</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">	<span class="n">ulong</span> <span class="n">hmask</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">switch</span> <span class="p">(</span><span class="n">extid</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nl">SBI_EXT_0_1_SET_TIMER</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="nf">sbi_timer_event_start</span><span class="p">((</span><span class="n">u64</span><span class="p">)</span><span class="n">regs</span><span class="o">-&gt;</span><span class="n">a0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nl">SBI_EXT_0_1_CONSOLE_PUTCHAR</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="nf">sbi_putc</span><span class="p">(</span><span class="n">regs</span><span class="o">-&gt;</span><span class="n">a0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">		<span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nl">SBI_EXT_0_1_CONSOLE_GETCHAR</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="n">ret</span> <span class="o">=</span> <span class="nf">sbi_getc</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">		<span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// ...
</span></span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这就把 <code>id</code> 与相应的服务函数绑定。一个<code>extid</code>对应一个<code>handler</code>。</p>
<p>我们可以在找到<code>SBI_EXT_0_1_CONSOLE_PUTCHAR</code>的值，是与 Linux 内核里定义的值是一致的。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// include/sbi/sbi_ecall_interface.h
</span></span></span><span class="line"><span class="cl"><span class="cm">/* SBI Extension IDs */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#define SBI_EXT_0_1_CONSOLE_PUTCHAR		0x1
</span></span></span></code></pre></div><h2 id="ecall-服务调用流程">ecall 服务调用流程</h2>
<ol>
<li>
<p>在 <code>firmware/fw_base.S</code> 中注册了 <code>Machine Mode</code> 的 <code>trap handler</code>，即 <code>sbi_trap_handler</code>；</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="nl">_start_warm:</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Setup trap handler */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">la</span>	<span class="no">a4</span><span class="p">,</span> <span class="no">_trap_handler</span>
</span></span><span class="line"><span class="cl">    <span class="nf">csrw</span>	<span class="no">CSR_MTVEC</span><span class="p">,</span> <span class="no">a4</span>  <span class="cm">/* CSR_MTVEC = _trap_handler */</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nl">_trap_handler:</span>
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_SAVE_AND_SETUP_SP_T0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_SAVE_MEPC_MSTATUS</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_SAVE_GENERAL_REGS_EXCEPT_SP_T0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_CALL_C_ROUTINE</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_RESTORE_GENERAL_REGS_EXCEPT_SP_T0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_RESTORE_MEPC_MSTATUS</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">TRAP_RESTORE_SP_T0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">mret</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="na">.macro</span>	<span class="no">TRAP_CALL_C_ROUTINE</span>
</span></span><span class="line"><span class="cl">    <span class="cm">/* Call C routine */</span>
</span></span><span class="line"><span class="cl">    <span class="nf">add</span>	<span class="no">a0</span><span class="p">,</span> <span class="no">sp</span><span class="p">,</span> <span class="no">zero</span>
</span></span><span class="line"><span class="cl">    <span class="nf">call</span>	<span class="no">sbi_trap_handler</span>
</span></span><span class="line"><span class="cl"><span class="na">.endm</span>
</span></span></code></pre></div></li>
<li>
<p>在 <code>lib/sbi/sbi_trap.c</code> 中定义了 <code>sbi_trap_handler</code>，处理各种 <code>mcause</code>，比如 <code>Illegal Instructions</code>，<code>Misaligned Load &amp; Store</code>, <code>Supervisor &amp; Machine Ecall</code> 等。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// lib/sbi/sbi_trap.c
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">sbi_trap_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">sbi_trap_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">switch</span> <span class="p">(</span><span class="n">mcause</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_ILLEGAL_INSTRUCTION</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span>  <span class="o">=</span> <span class="nf">sbi_illegal_insn_handler</span><span class="p">(</span><span class="n">mtval</span><span class="p">,</span> <span class="n">regs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_MISALIGNED_LOAD</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span> <span class="o">=</span> <span class="nf">sbi_misaligned_load_handler</span><span class="p">(</span><span class="n">mtval</span><span class="p">,</span> <span class="n">mtval2</span><span class="p">,</span> <span class="n">mtinst</span><span class="p">,</span> <span class="n">regs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_MISALIGNED_STORE</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span>  <span class="o">=</span> <span class="nf">sbi_misaligned_store_handler</span><span class="p">(</span><span class="n">mtval</span><span class="p">,</span> <span class="n">mtval2</span><span class="p">,</span> <span class="n">mtinst</span><span class="p">,</span> <span class="n">regs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_SUPERVISOR_ECALL</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">case</span> <span class="nl">CAUSE_MACHINE_ECALL</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span>  <span class="o">=</span> <span class="nf">sbi_ecall_handler</span><span class="p">(</span><span class="n">regs</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/* If the trap came from S or U mode, redirect it there */</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">epc</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-&gt;</span><span class="n">mepc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">cause</span> <span class="o">=</span> <span class="n">mcause</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">tval</span> <span class="o">=</span> <span class="n">mtval</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">tval2</span> <span class="o">=</span> <span class="n">mtval2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">trap</span><span class="p">.</span><span class="n">tinst</span> <span class="o">=</span> <span class="n">mtinst</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">rc</span> <span class="o">=</span> <span class="nf">sbi_trap_redirect</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">trap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span></code></pre></div></li>
<li>
<p>在 <code>lib/sbi/sbi_ecall.c</code> 中定义了处理 <code>ecall mcause</code> 的 <code>sbi_ecall_handler</code>，它遍历上面 <code>ecall_exts_list</code> 中注册的各种 <code>ecall</code> 服务。</p>
</li>
<li>
<p><code>sbi_ecall_handler</code> 根据 Linux 内核传递的 <code>ext (extension id)</code> 找到链表中对应的 <code>ecall</code> 服务，执行其中的 <code>handle</code> 函数，该函数根据 <code>fid</code> 执行具体的服务内容。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="c1">// lib/sbi/sbi_ecall.c
</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">sbi_ecall_handler</span><span class="p">(</span><span class="k">struct</span> <span class="n">sbi_trap_regs</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// ...
</span></span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">extension_id</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-&gt;</span><span class="n">a7</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">func_id</span> <span class="o">=</span> <span class="n">regs</span><span class="o">-&gt;</span><span class="n">a6</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">sbi_trap_info</span> <span class="n">trap</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
</span></span><span class="line"><span class="cl">    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">out_val</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 遍历所有 ecall 服务
</span></span></span><span class="line"><span class="cl">    <span class="n">ext</span> <span class="o">=</span> <span class="nf">sbi_ecall_find_extension</span><span class="p">(</span><span class="n">extension_id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">ext</span> <span class="o">&amp;&amp;</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="n">handle</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 如果找到了就执行
</span></span></span><span class="line"><span class="cl">        <span class="n">ret</span> <span class="o">=</span> <span class="n">ext</span><span class="o">-&gt;</span><span class="nf">handle</span><span class="p">(</span><span class="n">extension_id</span><span class="p">,</span> <span class="n">func_id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="n">regs</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">out_val</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">trap</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">extension_id</span> <span class="o">&gt;=</span> <span class="n">SBI_EXT_0_1_SET_TIMER</span> <span class="o">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">            <span class="n">extension_id</span> <span class="o">&lt;=</span> <span class="n">SBI_EXT_0_1_SHUTDOWN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">is_0_1_spec</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">ret</span> <span class="o">=</span> <span class="n">SBI_ENOTSUPP</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>我们可以发现 <code>extension_id</code> 就是 a7 寄存器，他和我们在 uCore OS 中定义的 <code>SBI_EXT_0_1_CONSOLE_PUTCHAR</code> 是一致的。</p>
</li>
</ol>
<h1 id="程序的内存布局与编译流程">程序的内存布局与编译流程</h1>
<h2 id="程序的内存布局">程序的内存布局</h2>
<h1 id="ucore-的编译系统">uCore 的编译系统</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-makefile" data-lang="makefile"><span class="line"><span class="cl"><span class="nf">.PHONY</span><span class="o">:</span> <span class="n">clean</span> <span class="n">build</span> <span class="n">user</span>
</span></span><span class="line"><span class="cl"><span class="c"># 设置伪目标clean、build和user，可以通过命令make来执行这些目标
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">all</span><span class="o">:</span> <span class="n">build_kernel</span>
</span></span><span class="line"><span class="cl"><span class="c"># 默认目标为build_kernel，即执行build_kernel目标下的指令
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">LOG</span> <span class="o">?=</span> error
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量LOG，默认值是error
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">K</span> <span class="o">=</span> os
</span></span><span class="line"><span class="cl"><span class="nv">TOOLPREFIX</span> <span class="o">=</span> riscv64-unknown-elf-
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CC</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>gcc
</span></span><span class="line"><span class="cl"><span class="nv">AS</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>gcc
</span></span><span class="line"><span class="cl"><span class="nv">LD</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>ld
</span></span><span class="line"><span class="cl"><span class="nv">OBJCOPY</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>objcopy
</span></span><span class="line"><span class="cl"><span class="nv">OBJDUMP</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>objdump
</span></span><span class="line"><span class="cl"><span class="nv">PY</span> <span class="o">=</span> python3
</span></span><span class="line"><span class="cl"><span class="nv">GDB</span> <span class="o">=</span> <span class="k">$(</span>TOOLPREFIX<span class="k">)</span>gdb
</span></span><span class="line"><span class="cl"><span class="nv">CP</span> <span class="o">=</span> cp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">MKDIR_P</span> <span class="o">=</span> mkdir -p
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">BUILDDIR</span> <span class="o">=</span> build
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">C_SRCS</span> <span class="o">=</span> <span class="k">$(</span>wildcard <span class="nv">$K</span>/*.c<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量C_SRCS，使用wildcard函数匹配所有以.c为后缀的文件，并存储在$K目录下
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">AS_SRCS</span> <span class="o">=</span> <span class="k">$(</span>wildcard <span class="nv">$K</span>/*.S<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量AS_SRCS，使用wildcard函数匹配所有以.S为后缀的文件，并存储在$K目录下
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">C_OBJS</span> <span class="o">=</span> <span class="k">$(</span>addprefix <span class="k">$(</span>BUILDDIR<span class="k">)</span>/, <span class="k">$(</span>addsuffix .o, <span class="k">$(</span>basename <span class="k">$(</span>C_SRCS<span class="k">))))</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量C_OBJS，通过addprefix和addsuffix函数将$(C_SRCS)中的路径替换为$(BUILDDIR)，并将后缀修改为.o
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">AS_OBJS</span> <span class="o">=</span> <span class="k">$(</span>addprefix <span class="k">$(</span>BUILDDIR<span class="k">)</span>/, <span class="k">$(</span>addsuffix .o, <span class="k">$(</span>basename <span class="k">$(</span>AS_SRCS<span class="k">))))</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量AS_OBJS，通过addprefix和addsuffix函数将$(AS_SRCS)中的路径替换为$(BUILDDIR)，并将后缀修改为.o
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">OBJS</span> <span class="o">=</span> <span class="k">$(</span>C_OBJS<span class="k">)</span> <span class="k">$(</span>AS_OBJS<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量OBJS，其值为$(C_OBJS)和$(AS_OBJS)的组合
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">HEADER_DEP</span> <span class="o">=</span> <span class="k">$(</span>addsuffix .d, <span class="k">$(</span>basename <span class="k">$(</span>C_OBJS<span class="k">)))</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量HEADER_DEP，通过addsuffix函数将$(C_OBJS)中的后缀修改为.d
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">-include</span> <span class="k">$(</span><span class="nv">HEADER_DEP</span><span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 包含$(HEADER_DEP)中的.d文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">=</span> -Wall -Werror -O -fno-omit-frame-pointer -ggdb
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量CFLAGS，并赋值为-Wall -Werror -O -fno-omit-frame-pointer -ggdb
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -MD
</span></span><span class="line"><span class="cl"><span class="c"># 将-MD选项追加到CFLAGS变量中，用于自动生成依赖关系文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -mcmodel<span class="o">=</span>medany
</span></span><span class="line"><span class="cl"><span class="c"># 将-mcmodel=medany选项追加到CFLAGS变量中，用于指定内存模型
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -ffreestanding -fno-common -nostdlib -mno-relax
</span></span><span class="line"><span class="cl"><span class="c"># 将-ffreestanding -fno-common -nostdlib -mno-relax选项追加到CFLAGS变量中，用于编译无操作系统环境下的程序
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -I<span class="nv">$K</span>
</span></span><span class="line"><span class="cl"><span class="c"># 将-I$K选项追加到CFLAGS变量中，用于指定头文件搜索路径为$K目录下
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> <span class="k">$(</span>shell <span class="k">$(</span>CC<span class="k">)</span> -fno-stack-protector -E -x c /dev/null &gt;/dev/null 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> -fno-stack-protector<span class="k">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># 将$(CC) -fno-stack-protector -E -x c /dev/null &gt;/dev/null 2&gt;&amp;1 &amp;&amp; echo -fno-stack-protector命令执行结果追加到CFLAGS变量中，用于禁用栈保护机制
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">error)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_ERROR
</span></span><span class="line"><span class="cl"><span class="err">else</span> <span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">warn)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_WARN
</span></span><span class="line"><span class="cl"><span class="err">else</span> <span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">info)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_INFO
</span></span><span class="line"><span class="cl"><span class="err">else</span> <span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">debug)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_DEBUG
</span></span><span class="line"><span class="cl"><span class="err">else</span> <span class="err">ifeq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">LOG</span><span class="k">)</span><span class="err">,</span> <span class="err">trace)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -D LOG_LEVEL_TRACE
</span></span><span class="line"><span class="cl"><span class="err">endif</span>
</span></span><span class="line"><span class="cl"><span class="c"># 根据$(LOG)变量的值，向CFLAGS变量追加相应的预处理器选项，相当于添加了一个宏定义，log.h中的LOG_LEVEL_ERROR等宏定义会根据这个宏定义来决定是否生效
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Disable PIE when possible (for Ubuntu 16.10 toolchain)
</span></span></span><span class="line"><span class="cl"><span class="err">ifneq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">shell</span> <span class="k">$(</span><span class="nv">CC</span><span class="k">)</span> -<span class="nv">dumpspecs</span> 2&gt;/<span class="nv">dev</span>/<span class="nv">null</span> | <span class="nv">grep</span> -<span class="nv">e</span> &#39;[^<span class="nv">f</span>]<span class="nv">no</span>-<span class="nv">pie</span>&#39;<span class="k">)</span><span class="err">,)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -fno-pie -no-pie
</span></span><span class="line"><span class="cl"><span class="err">endif</span>
</span></span><span class="line"><span class="cl"><span class="err">ifneq</span> <span class="err">(</span><span class="k">$(</span><span class="nv">shell</span> <span class="k">$(</span><span class="nv">CC</span><span class="k">)</span> -<span class="nv">dumpspecs</span> 2&gt;/<span class="nv">dev</span>/<span class="nv">null</span> | <span class="nv">grep</span> -<span class="nv">e</span> &#39;[^<span class="nv">f</span>]<span class="nv">nopie</span>&#39;<span class="k">)</span><span class="err">,)</span>
</span></span><span class="line"><span class="cl"><span class="nv">CFLAGS</span> <span class="o">+=</span> -fno-pie -nopie
</span></span><span class="line"><span class="cl"><span class="err">endif</span>
</span></span><span class="line"><span class="cl"><span class="c"># 根据系统环境判断是否支持PIE（位置无关执行）选项，并根据情况向CFLAGS变量追加相应的选项
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">LDFLAGS</span> <span class="o">=</span> -z max-page-size<span class="o">=</span><span class="m">4096</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个变量LDFLAGS，并赋值为-z max-page-size=4096
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(AS_OBJS)</span><span class="o">:</span> <span class="k">$(</span><span class="nv">BUILDDIR</span><span class="k">)</span>/$<span class="n">K</span>/%.<span class="n">o</span> : $<span class="n">K</span>/%.<span class="n">S</span>
</span></span><span class="line"><span class="cl">    @mkdir -p <span class="k">$(</span>@D<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -c $&lt; -o <span class="nv">$@</span>
</span></span><span class="line"><span class="cl"><span class="c"># 规则：生成$(AS_OBJS)目标所需的依赖文件$(BUILDDIR)/$K/%.o，依赖于$K/%.S，并通过$(CC)命令编译生成目标文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(C_OBJS)</span><span class="o">:</span> <span class="k">$(</span><span class="nv">BUILDDIR</span><span class="k">)</span>/$<span class="n">K</span>/%.<span class="n">o</span> : $<span class="n">K</span>/%.<span class="n">c</span>  <span class="k">$(</span><span class="nv">BUILDDIR</span><span class="k">)</span>/$<span class="n">K</span>/%.<span class="n">d</span>
</span></span><span class="line"><span class="cl">    @mkdir -p <span class="k">$(</span>@D<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>CC<span class="k">)</span> <span class="k">$(</span>CFLAGS<span class="k">)</span> -c $&lt; -o <span class="nv">$@</span>
</span></span><span class="line"><span class="cl"><span class="c"># 规则：生成$(C_OBJS)目标所需的依赖文件$(BUILDDIR)/$K/%.o，依赖于$K/%.c和$(BUILDDIR)/$K/%.d，并通过$(CC)命令编译生成目标文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">$(HEADER_DEP)</span><span class="o">:</span> <span class="k">$(</span><span class="nv">BUILDDIR</span><span class="k">)</span>/$<span class="n">K</span>/%.<span class="n">d</span> : $<span class="n">K</span>/%.<span class="n">c</span>
</span></span><span class="line"><span class="cl">    @mkdir -p <span class="k">$(</span>@D<span class="k">)</span>
</span></span><span class="line"><span class="cl">    @set -e<span class="p">;</span> rm -f <span class="nv">$@</span><span class="p">;</span> <span class="k">$(</span>CC<span class="k">)</span> -MM $&lt; <span class="k">$(</span>INCLUDEFLAGS<span class="k">)</span> &gt; <span class="nv">$@</span>.<span class="nv">$$$$</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">        sed <span class="s1">&#39;s,\($*\)\.o[ :]*,\1.o $@ : ,g&#39;</span> &lt; <span class="nv">$@</span>.<span class="nv">$$$$</span> &gt; <span class="nv">$@</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">        rm -f <span class="nv">$@</span>.<span class="nv">$$$$</span>
</span></span><span class="line"><span class="cl"><span class="c"># 规则：生成$(HEADER_DEP)目标所需的依赖文件$(BUILDDIR)/$K/%.d，依赖于$K/%.c，并通过$(CC)命令生成依赖关系文件
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">build</span><span class="o">:</span> <span class="n">build</span>/<span class="n">kernel</span>
</span></span><span class="line"><span class="cl"><span class="c"># 定义一个目标build，其依赖于build/kernel
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">build/kernel</span><span class="o">:</span> <span class="k">$(</span><span class="nv">OBJS</span><span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>LD<span class="k">)</span> <span class="k">$(</span>LDFLAGS<span class="k">)</span> -T os/kernel.ld -o <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel <span class="k">$(</span>OBJS<span class="k">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>OBJDUMP<span class="k">)</span> -S <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel &gt; <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel.asm
</span></span><span class="line"><span class="cl">    <span class="k">$(</span>OBJDUMP<span class="k">)</span> -t <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel <span class="p">|</span> sed <span class="s1">&#39;1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d&#39;</span> &gt; <span class="k">$(</span>BUILDDIR<span class="k">)</span>/kernel.sym
</span></span><span class="line"><span class="cl">    @echo <span class="s1">&#39;Build kernel done&#39;</span>
</span></span><span class="line"><span class="cl"><span class="c"># 规则：生成build/kernel目标，依赖于$(OBJS)，通过$(LD)命令连接生成kernel，并通过$(OBJDUMP)命令生成汇编文件和符号表
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">clean</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">    rm -rf <span class="k">$(</span>BUILDDIR<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># BOARD
</span></span></span><span class="line"><span class="cl"><span class="nv">BOARD</span>		<span class="o">?=</span> qemu
</span></span><span class="line"><span class="cl"><span class="nv">SBI</span>			<span class="o">?=</span> rustsbi
</span></span><span class="line"><span class="cl"><span class="nv">BOOTLOADER</span>	<span class="o">:=</span> ./bootloader/rustsbi-qemu.bin
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">QEMU</span> <span class="o">=</span> qemu-system-riscv64
</span></span><span class="line"><span class="cl"><span class="nv">QEMUOPTS</span> <span class="o">=</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	-nographic <span class="se">\
</span></span></span><span class="line"><span class="cl">	-machine virt <span class="se">\
</span></span></span><span class="line"><span class="cl">	-bios <span class="k">$(</span>BOOTLOADER<span class="k">)</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	-kernel build/kernel	<span class="se">\
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">run</span><span class="o">:</span> <span class="n">build</span>/<span class="n">kernel</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>QEMU<span class="k">)</span> <span class="k">$(</span>QEMUOPTS<span class="k">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># QEMU&#39;s gdb stub command line changed in 0.11
</span></span></span><span class="line"><span class="cl"><span class="nv">QEMUGDB</span> <span class="o">=</span> <span class="k">$(</span>shell <span class="k">if</span> <span class="k">$(</span>QEMU<span class="k">)</span> -help <span class="p">|</span> grep -q <span class="s1">&#39;^-gdb&#39;</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	<span class="k">then</span> <span class="nb">echo</span> <span class="s2">&#34;-gdb tcp::15234&#34;</span><span class="p">;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">	<span class="k">else</span> <span class="nb">echo</span> <span class="s2">&#34;-s -p 15234&#34;</span><span class="p">;</span> <span class="k">fi</span><span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># 启动QEMU并通过GDB调试，此时QEMu会进入后台运行，并暂停执行，等待GDB连接
</span></span></span><span class="line"><span class="cl"><span class="c"># 连接的GDB端口为15234
</span></span></span><span class="line"><span class="cl"><span class="nf">debug</span><span class="o">:</span> <span class="n">build</span>/<span class="n">kernel</span> .<span class="n">gdbinit</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>QEMU<span class="k">)</span> <span class="k">$(</span>QEMUOPTS<span class="k">)</span> -S <span class="k">$(</span>QEMUGDB<span class="k">)</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="cl">	sleep <span class="m">1</span>
</span></span><span class="line"><span class="cl">	<span class="k">$(</span>GDB<span class="k">)</span>
</span></span></code></pre></div><p>编译、运行 uCore 的一些常用命令有如下一些，涉及了后续章节中引入的测试用例中的命令：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make run
</span></span><span class="line"><span class="cl">make debug
</span></span><span class="line"><span class="cl">make clean
</span></span><span class="line"><span class="cl"><span class="c1"># 编译测试用例的前四章</span>
</span></span><span class="line"><span class="cl">make user <span class="nv">CHAPTER</span><span class="o">=</span><span class="m">4</span> <span class="nv">LOG</span><span class="o">=</span>trace
</span></span><span class="line"><span class="cl"><span class="c1"># 编译测试用例的第四章</span>
</span></span><span class="line"><span class="cl">make user <span class="nv">CHAPTER</span><span class="o">=</span>4_only <span class="nv">LOG</span><span class="o">=</span>trace
</span></span><span class="line"><span class="cl"><span class="c1"># 只运行测试用例的第四章</span>
</span></span><span class="line"><span class="cl">make <span class="nb">test</span> <span class="nv">CHAPTER</span><span class="o">=</span>4_only    
</span></span></code></pre></div><h1 id="附录">附录</h1>
<p>makefile 和 qemu</p>
<p>AS = $(TOOLPREFIX)gas  &gt; AS = $(TOOLPREFIX)as</p>
<h1 id="参考资料">参考资料</h1>
<ul>
<li><a href="https://www.jianshu.com/p/790fc612aaa5">终端颜色控制 - 简书</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>uCore 实验第 5 章 - 进程及进程管理</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC5%E7%AB%A0-%E8%BF%9B%E7%A8%8B%E5%8F%8A%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/</link>
      <pubDate>Fri, 08 Sep 2023 10:01:20 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC5%E7%AB%A0-%E8%BF%9B%E7%A8%8B%E5%8F%8A%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/</guid>
      <description>&lt;p&gt;首先，&lt;code&gt;.section .data&lt;/code&gt; 表示定义了一个数据段，在这个段中定义了一系列的全局变量。其中，&lt;code&gt;_app_num&lt;/code&gt; 是一个标签，表示一个 64 位的整数，初始值为 23。接下来是一系列的标签，分别代表了应用程序的起始地址，每个标签都是 64 位的整数。&lt;/p&gt;
&lt;p&gt;接着，&lt;code&gt;.section .data&lt;/code&gt; 后面又出现了一个标签 &lt;code&gt;_app_names&lt;/code&gt;，它是一个字符串数组，包含了一组字符串，分别命名为 &amp;ldquo;ch2b_exit&amp;rdquo;、&amp;ldquo;ch2b_hello_world&amp;rdquo;、&amp;ldquo;ch2b_power&amp;rdquo; 等等。这些字符串名字对应了前面定义的应用程序的起始地址。&lt;/p&gt;
&lt;p&gt;再往下，出现了一个标签 &lt;code&gt;INIT_PROC&lt;/code&gt;，它是一个字符串，表示初始化进程的名称，值为 &amp;ldquo;usershell&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;之后，每个应用程序都有自己的标签和段名，比如 &lt;code&gt;app_0_start&lt;/code&gt;、&lt;code&gt;app_1_start&lt;/code&gt; 等等。每个标签都包含一个指令 &lt;code&gt;.incbin&lt;/code&gt;，它用于将一个二进制文件（以字符串形式指定文件路径）插入到当前段中。&lt;/p&gt;
&lt;h1 id=&#34;进程初始化分析&#34;&gt;进程初始化分析&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;scheduler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;fetch_task&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 获取下一个要执行的进程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;swtch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;curenv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nextenv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 切换到下一个进程上下文
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Per-process state
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;procstate&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;// 进程状态
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;               &lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 进程 ID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 进程用户栈虚拟地址 (用户页表)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 进程内核栈虚拟地址 (内核页表)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 进程中断帧
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 用于保存进程内核态的寄存器信息，进程切换时使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;pagetable_t&lt;/span&gt;       &lt;span class=&#34;n&#34;&gt;pagetable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// User page table
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;max_page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;program_brk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;heap_bottom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;parent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Parent process
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;exit_code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FD_BUFFER_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 系统调用次数统计
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 进程开始运行时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vma&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vmas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NVMA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 虚拟内存区域
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;wait-系统调用的功能&#34;&gt;wait 系统调用的功能&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;wait&lt;/code&gt; 系统调用是用于处理子进程终止状态的系统调用。其主要功能是等待子进程的终止，并获取子进程的退出状态信息。在操作系统中，当一个父进程创建了一个子进程后，通常会使用 &lt;code&gt;wait&lt;/code&gt; 来等待子进程的终止，以便进行后续的处理，如回收子进程的资源或获取其运行结果。&lt;/p&gt;
&lt;p&gt;以下是 &lt;code&gt;wait&lt;/code&gt; 系统调用的主要功能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;等待子进程终止&lt;/strong&gt;：父进程调用 &lt;code&gt;wait&lt;/code&gt; 系统调用后，会进入阻塞状态，等待子进程终止。如果子进程已经终止，那么 &lt;code&gt;wait&lt;/code&gt; 立即返回，否则父进程会一直等待直到子进程终止。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;获取子进程的退出状态&lt;/strong&gt;：&lt;code&gt;wait&lt;/code&gt; 系统调用会获取子进程的退出状态信息，包括子进程的退出码（通常是一个整数）。这个退出码可以告诉父进程子进程的终止情况，例如是否成功执行等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;回收子进程资源&lt;/strong&gt;：一旦子进程终止，其占用的系统资源（如内存、文件描述符等）通常需要由父进程来回收，以避免资源泄漏。&lt;code&gt;wait&lt;/code&gt; 系统调用在等待子进程终止后，会自动回收这些资源。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;处理僵尸进程&lt;/strong&gt;：在某些情况下，子进程可能会在终止后成为僵尸进程，即已经终止但其进程描述符仍然存在。父进程可以使用 &lt;code&gt;wait&lt;/code&gt; 来回收这些僵尸进程，释放相关资源。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;exec&lt;/code&gt;、&lt;code&gt;fork&lt;/code&gt; 和 &lt;code&gt;spawn&lt;/code&gt; 是操作系统中常见的进程管理系统调用，各自具有不同的功能和用途：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;exec&lt;/code&gt; 系统调用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：&lt;code&gt;exec&lt;/code&gt; 系统调用用于在当前进程的上下文中加载并执行一个新的程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：通常在一个进程需要替换自身的执行映像时使用。它会加载一个新的可执行文件，覆盖当前进程的地址空间和代码段，然后开始执行新的程序。这个新程序可以是完全不同的程序，从而允许进程动态切换到不同的应用程序，而不需要创建新的进程。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;fork&lt;/code&gt; 系统调用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：&lt;code&gt;fork&lt;/code&gt; 系统调用用于创建一个与当前进程几乎完全相同的新进程，包括代码、数据和上下文等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：通常用于创建新的进程，新进程称为子进程，它从父进程继承了大部分状态，然后可以在独立的地址空间中执行不同的操作。&lt;code&gt;fork&lt;/code&gt; 创建的子进程是父进程的副本，可以并行执行不同的任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;spawn&lt;/code&gt; 系统调用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：&lt;code&gt;spawn&lt;/code&gt; 系统调用通常用于创建新的进程并执行指定的程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：类似于 &lt;code&gt;fork&lt;/code&gt;，它也创建了一个新的进程，但不像 &lt;code&gt;fork&lt;/code&gt; 那样完全复制父进程。相反，&lt;code&gt;spawn&lt;/code&gt; 允许你指定一个新程序的路径和参数，而不是完全复制当前进程的状态。这使得它更适合用于启动新程序，而不是简单地创建一个进程副本。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;exec&lt;/code&gt; 用于替换当前进程的执行映像，允许加载和执行新程序。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fork&lt;/code&gt; 用于创建一个几乎与父进程相同的新进程，新进程成为父进程的副本。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spawn&lt;/code&gt; 通常用于创建一个新进程并执行指定的程序，允许指定不同的程序路径和参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;附录&#34;&gt;附录&lt;/h1&gt;
&lt;p&gt;本章任务：
在次 -&amp;gt; 在此&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>首先，<code>.section .data</code> 表示定义了一个数据段，在这个段中定义了一系列的全局变量。其中，<code>_app_num</code> 是一个标签，表示一个 64 位的整数，初始值为 23。接下来是一系列的标签，分别代表了应用程序的起始地址，每个标签都是 64 位的整数。</p>
<p>接着，<code>.section .data</code> 后面又出现了一个标签 <code>_app_names</code>，它是一个字符串数组，包含了一组字符串，分别命名为 &ldquo;ch2b_exit&rdquo;、&ldquo;ch2b_hello_world&rdquo;、&ldquo;ch2b_power&rdquo; 等等。这些字符串名字对应了前面定义的应用程序的起始地址。</p>
<p>再往下，出现了一个标签 <code>INIT_PROC</code>，它是一个字符串，表示初始化进程的名称，值为 &ldquo;usershell&rdquo;。</p>
<p>之后，每个应用程序都有自己的标签和段名，比如 <code>app_0_start</code>、<code>app_1_start</code> 等等。每个标签都包含一个指令 <code>.incbin</code>，它用于将一个二进制文件（以字符串形式指定文件路径）插入到当前段中。</p>
<h1 id="进程初始化分析">进程初始化分析</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">scheduler</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="nf">fetch_task</span><span class="p">()</span> <span class="c1">// 获取下一个要执行的进程
</span></span></span><span class="line"><span class="cl">    <span class="nf">swtch</span><span class="p">(</span><span class="o">&amp;</span><span class="n">curenv</span><span class="o">-&gt;</span><span class="n">context</span><span class="p">,</span> <span class="n">nextenv</span><span class="o">-&gt;</span><span class="n">context</span><span class="p">)</span> <span class="c1">// 切换到下一个进程上下文
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// Per-process state
</span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="n">proc</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">enum</span> <span class="n">procstate</span>    <span class="n">state</span><span class="p">;</span>     <span class="c1">// 进程状态
</span></span></span><span class="line"><span class="cl">    <span class="kt">int</span>               <span class="n">pid</span><span class="p">;</span>       <span class="c1">// 进程 ID
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">ustack</span><span class="p">;</span>    <span class="c1">// 进程用户栈虚拟地址 (用户页表)
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">kstack</span><span class="p">;</span>    <span class="c1">// 进程内核栈虚拟地址 (内核页表)
</span></span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">trapframe</span> <span class="o">*</span><span class="n">trapframe</span><span class="p">;</span> <span class="c1">// 进程中断帧
</span></span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">context</span>    <span class="n">context</span><span class="p">;</span> <span class="c1">// 用于保存进程内核态的寄存器信息，进程切换时使用
</span></span></span><span class="line"><span class="cl">    <span class="kt">pagetable_t</span>       <span class="n">pagetable</span><span class="p">;</span> <span class="c1">// User page table
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">max_page</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">program_brk</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">heap_bottom</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span>     <span class="n">parent</span><span class="p">;</span> <span class="c1">// Parent process
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>            <span class="n">exit_code</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span>     <span class="n">files</span><span class="p">[</span><span class="n">FD_BUFFER_SIZE</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">uint32</span>     <span class="n">syscall_times</span><span class="p">[</span><span class="n">MAX_SYSCALL_NUM</span><span class="p">];</span> <span class="c1">// 系统调用次数统计
</span></span></span><span class="line"><span class="cl">    <span class="n">uint64</span>     <span class="n">start_time</span><span class="p">;</span>                     <span class="c1">// 进程开始运行时间
</span></span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">vma</span> <span class="n">vmas</span><span class="p">[</span><span class="n">NVMA</span><span class="p">];</span>                     <span class="c1">// 虚拟内存区域
</span></span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="wait-系统调用的功能">wait 系统调用的功能</h2>
<p><code>wait</code> 系统调用是用于处理子进程终止状态的系统调用。其主要功能是等待子进程的终止，并获取子进程的退出状态信息。在操作系统中，当一个父进程创建了一个子进程后，通常会使用 <code>wait</code> 来等待子进程的终止，以便进行后续的处理，如回收子进程的资源或获取其运行结果。</p>
<p>以下是 <code>wait</code> 系统调用的主要功能：</p>
<ol>
<li>
<p><strong>等待子进程终止</strong>：父进程调用 <code>wait</code> 系统调用后，会进入阻塞状态，等待子进程终止。如果子进程已经终止，那么 <code>wait</code> 立即返回，否则父进程会一直等待直到子进程终止。</p>
</li>
<li>
<p><strong>获取子进程的退出状态</strong>：<code>wait</code> 系统调用会获取子进程的退出状态信息，包括子进程的退出码（通常是一个整数）。这个退出码可以告诉父进程子进程的终止情况，例如是否成功执行等。</p>
</li>
<li>
<p><strong>回收子进程资源</strong>：一旦子进程终止，其占用的系统资源（如内存、文件描述符等）通常需要由父进程来回收，以避免资源泄漏。<code>wait</code> 系统调用在等待子进程终止后，会自动回收这些资源。</p>
</li>
<li>
<p><strong>处理僵尸进程</strong>：在某些情况下，子进程可能会在终止后成为僵尸进程，即已经终止但其进程描述符仍然存在。父进程可以使用 <code>wait</code> 来回收这些僵尸进程，释放相关资源。</p>
</li>
</ol>
<p><code>exec</code>、<code>fork</code> 和 <code>spawn</code> 是操作系统中常见的进程管理系统调用，各自具有不同的功能和用途：</p>
<ol>
<li>
<p><strong><code>exec</code> 系统调用</strong>：</p>
<ul>
<li><strong>功能</strong>：<code>exec</code> 系统调用用于在当前进程的上下文中加载并执行一个新的程序。</li>
<li><strong>用途</strong>：通常在一个进程需要替换自身的执行映像时使用。它会加载一个新的可执行文件，覆盖当前进程的地址空间和代码段，然后开始执行新的程序。这个新程序可以是完全不同的程序，从而允许进程动态切换到不同的应用程序，而不需要创建新的进程。</li>
</ul>
</li>
<li>
<p><strong><code>fork</code> 系统调用</strong>：</p>
<ul>
<li><strong>功能</strong>：<code>fork</code> 系统调用用于创建一个与当前进程几乎完全相同的新进程，包括代码、数据和上下文等。</li>
<li><strong>用途</strong>：通常用于创建新的进程，新进程称为子进程，它从父进程继承了大部分状态，然后可以在独立的地址空间中执行不同的操作。<code>fork</code> 创建的子进程是父进程的副本，可以并行执行不同的任务。</li>
</ul>
</li>
<li>
<p><strong><code>spawn</code> 系统调用</strong>：</p>
<ul>
<li><strong>功能</strong>：<code>spawn</code> 系统调用通常用于创建新的进程并执行指定的程序。</li>
<li><strong>用途</strong>：类似于 <code>fork</code>，它也创建了一个新的进程，但不像 <code>fork</code> 那样完全复制父进程。相反，<code>spawn</code> 允许你指定一个新程序的路径和参数，而不是完全复制当前进程的状态。这使得它更适合用于启动新程序，而不是简单地创建一个进程副本。</li>
</ul>
</li>
</ol>
<p>总结：</p>
<ul>
<li><code>exec</code> 用于替换当前进程的执行映像，允许加载和执行新程序。</li>
<li><code>fork</code> 用于创建一个几乎与父进程相同的新进程，新进程成为父进程的副本。</li>
<li><code>spawn</code> 通常用于创建一个新进程并执行指定的程序，允许指定不同的程序路径和参数。</li>
</ul>
<h1 id="附录">附录</h1>
<p>本章任务：
在次 -&gt; 在此</p>
]]></content:encoded>
    </item>
    <item>
      <title>uCore 实验第 4 章 - 地址空间</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC4%E7%AB%A0-%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4/</link>
      <pubDate>Mon, 04 Sep 2023 11:11:48 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC4%E7%AB%A0-%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;为何指定 TRAMPOLINE 和 TRAPFRAME 在 va 的最高位？
TRAMPOLINE 和 TRAPFRAME 被定义在最高的虚拟内存地址上，是因为它们在操作系统的内存布局中起着重要作用。
TRAMPOLINE 被用作从用户模式切换到内核模式的跳转目标。当发生异常或中断时，处理器将从用户模式切换到内核模式，并将控制权转移到内核中预定义的位置，也就是陷阱处理程序。TRAMPOLINE 页面被映射到最高虚拟地址，以便处理器能够在这个转换过程中方便地引用它。通过将其放置在最高地址，确保了无论系统的具体内存布局如何，它始终是可访问的。
另一方面，TRAPFRAME 用于在发生异常或中断时存储机器状态。它包含寄存器、标志和其他操作系统处理异常所需的信息。TRAPFRAME 也被放置在最高的虚拟地址上，以确保它易于访问，并且陷阱处理程序可以高效地访问它。
通过将 TRAMPOLINE 和 TRAPFRAME 定义在最高的虚拟内存地址上，内核可以方便而可靠地处理异常和中断，而无需关心它们在内存中的特定位置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;如何确定分页方案---satp&#34;&gt;如何确定分页方案 - satp&lt;/h1&gt;
&lt;p&gt;在 MMU 没有使能的情况下，虚拟地址和物理地址是相同的。在 MMU 使能的情况下，虚拟地址会被转换成物理地址。这个转换过程是由操作系统来管理的，操作系统需要维护一个数据结构来记录虚拟地址和物理地址的映射关系。这个数据结构就是页表。&lt;/p&gt;
&lt;p&gt;转换的过程需要分页机制，分页机制有多种。RISC-V 的分页方案以 SvX 的模式命名，其中 X 是以位为单位的&lt;strong&gt;虚拟地址的长度&lt;/strong&gt;。在 RV64 架构下，RISC-V 支持多种分页方案，包括 Sv39，Sv48，Sv57 以及 Sv64。Sv39 最大支持 39 位的虚拟地址，这意味着它可以支持 512 GB 的虚拟地址空间。Sv48 最大支持 48 位的虚拟地址，这意味着它可以支持 256 TB 的虚拟地址空间。我们将在本章中实现 Sv39 分页方案。&lt;/p&gt;
&lt;p&gt;如何开启分页机制呢？RISC-V 的分页机制是通过 satp（Supervisor address translation and protection）寄存器来开启的。satp 寄存器字段分布如下：&lt;/p&gt;
&lt;p&gt;

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

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

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

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

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

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

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

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

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

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

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>当 satp 寄存器中开启分页时，S 模式和 U 模式中访存的地址都会被视为虚拟地址，需要将其转换为物理地址。虚拟地址转换物理地址的过程如下：</p>
<ul>
<li>从 satp 寄存器中读取 PPN，得到根页表的物理地址，为了表述方便，我们将其记做三级页表基地址 satp.PPN；</li>
<li>从虚拟地址中取出三级虚拟页号 L2</li>
<li>处理器会读取地址位于 satp.PPN * 4096 + L2 * 4 的页表项，得到下一级页表的基地址 L1.PPN；</li>
<li>从虚拟地址中取出二级虚拟页号 L1</li>
<li>处理器会读取地址位于 L1.PPN * 4096 + L1 * 4 的页表项，得到下一级页表的基地址 L0.PPN；</li>
<li>从虚拟地址中取出一级虚拟页号 L0</li>
<li>处理器会读取地址位于 L0.PPN * 4096 + L0 * 4 的页表项，得到物理页号 PPN；</li>
<li>将 PPN 和虚拟地址的低 12 位也就是 Offset 拼接起来，得到物理地址。</li>
</ul>
<p>我们看代码中是如何实现的：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define PTE2PA(pte) (((pte) &gt;&gt; 10) &lt;&lt; 12)
</span></span></span><span class="line"><span class="cl"><span class="c1">// 从虚拟地址中提取三个 9 位的页表索引
</span></span></span><span class="line"><span class="cl"><span class="cp">#define PXMASK 0x1FF </span><span class="c1">// 9
</span></span></span><span class="line"><span class="cl"><span class="c1">// PGSHIFT = 12，这段宏定义用于定位 VPNx 的位置
</span></span></span><span class="line"><span class="cl"><span class="cp">#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
</span></span></span><span class="line"><span class="cl"><span class="c1">// 从虚拟地址 VA 中提取出第 level 级页表的索引
</span></span></span><span class="line"><span class="cl"><span class="cp">#define PX(level, va) ((((uint64)(va)) &gt;&gt; PXSHIFT(level)) &amp; PXMASK)
</span></span></span></code></pre></div><p>上面这三个工具宏可以用来提取虚拟页号 VPN。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 返回页表 pagetable 中与虚拟地址 va 对应的 PTE 的地址。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 如果 alloc != 0，则创建所需的页表页。
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// RISC-V Sv39 方案有三级页表页。一个页表页包含 512 个 64 位的 PTEs。
</span></span></span><span class="line"><span class="cl"><span class="c1">// 一个 64 位的虚拟地址被分为五个字段：
</span></span></span><span class="line"><span class="cl"><span class="c1">//   39..63 -- 必须为零。
</span></span></span><span class="line"><span class="cl"><span class="c1">//   30..38 -- 2 级索引的 9 位。
</span></span></span><span class="line"><span class="cl"><span class="c1">//   21..29 -- 1 级索引的 9 位。
</span></span></span><span class="line"><span class="cl"><span class="c1">//   12..20 -- 0 级索引的 9 位。
</span></span></span><span class="line"><span class="cl"><span class="c1">//    0..11 -- 页面内的 12 位字节偏移量。
</span></span></span><span class="line"><span class="cl"><span class="c1">// pagetable 页表
</span></span></span><span class="line"><span class="cl"><span class="c1">// va 虚拟地址
</span></span></span><span class="line"><span class="cl"><span class="c1">// alloc 页表项不存在时是否分配
</span></span></span><span class="line"><span class="cl"><span class="kt">pte_t</span> <span class="o">*</span><span class="nf">walk</span><span class="p">(</span><span class="kt">pagetable_t</span> <span class="n">pagetable</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">va</span><span class="p">,</span> <span class="kt">int</span> <span class="n">alloc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">va</span> <span class="o">&gt;=</span> <span class="n">MAXVA</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nf">panic</span><span class="p">(</span><span class="s">&#34;walk&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">level</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">level</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span> <span class="n">level</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">pte_t</span> <span class="o">*</span><span class="n">pte</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">pagetable</span><span class="p">[</span><span class="nf">PX</span><span class="p">(</span><span class="n">level</span><span class="p">,</span> <span class="n">va</span><span class="p">)];</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 通过 PTE 的标志位判断每一级的 pte 是否是有效的（V 位）
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">pte</span> <span class="o">&amp;</span> <span class="n">PTE_V</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">pagetable</span> <span class="o">=</span> <span class="p">(</span><span class="kt">pagetable_t</span><span class="p">)</span><span class="nf">PTE2PA</span><span class="p">(</span><span class="o">*</span><span class="n">pte</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 如果该项无效且 alloc 标志被设置，则分配一个新的页表
</span></span></span><span class="line"><span class="cl">            <span class="c1">// 如果 alloc 参数=0 或者已经没有空闲的内存了，那么遇到中途 V=0 的 pte 整个 walk 过程就会直接退出
</span></span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">alloc</span> <span class="o">||</span> <span class="p">(</span><span class="n">pagetable</span> <span class="o">=</span> <span class="p">(</span><span class="kt">pde_t</span> <span class="o">*</span><span class="p">)</span><span class="nf">kalloc</span><span class="p">())</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 清空分配的页表
</span></span></span><span class="line"><span class="cl">            <span class="nf">memset</span><span class="p">(</span><span class="n">pagetable</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">PGSIZE</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 更新页表项，将其指向新分配的页表，并设置有效位 PTE_V
</span></span></span><span class="line"><span class="cl">            <span class="o">*</span><span class="n">pte</span> <span class="o">=</span> <span class="nf">PA2PTE</span><span class="p">(</span><span class="n">pagetable</span><span class="p">)</span> <span class="o">|</span> <span class="n">PTE_V</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// 返回最低级和虚拟地址的页表项，不是返回物理地址
</span></span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="o">&amp;</span><span class="n">pagetable</span><span class="p">[</span><span class="nf">PX</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">va</span><span class="p">)];</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>每次从虚拟地址 va 中提取出一个虚拟页号，然后根据这个虚拟页号从页表中取出下一级页表的基地址。如果这个页表项无效，那么根据 alloc 参数决定是否分配一个新的页表。如果 alloc 参数为 0 或者已经没有空闲的内存了，那么遇到中途 V=0 的 pte 整个 walk 过程就会直接退出。如果 alloc 参数为 1，那么就会分配一个新的页表，然后将这个页表项指向新分配的页表，并设置有效位 PTE_V。</p>
<p>我们可以发现 walk 返回的结果不是物理地址，而是页表项的地址。这是因为 walk 函数的作用是将虚拟地址转换为物理地址，而页表项中的 PPN 只是物理地址的一部分，<strong>还需要加上虚拟地址的低 12 位偏移量才能得到物理地址</strong>。</p>
<h2 id="如何建立页表">如何建立页表</h2>
<p>前面的过程实际上是以用户的角度来考虑的，也就是给你一个虚拟地址按照分页的规则将其转化成物理地址就能访问了。但是作为一个操作系统，我们还需要多考虑一下，页表是哪来的？我们知道从虚拟地址中去获取页表地址，但是<strong>页表的内容是哪来的呢</strong>？页表是如何建立起来的呢？这些是需要操作系统来完成的。</p>
<p>建立页表也就是建立虚拟地址到物理地址的映射关系。也就是给你一个虚拟地址，你需要告诉我如何查到物理地址，实际上这个过程就是建立页表的过程。这个过程也是通过 walk 函数来完成的，从上文我们知道如果页表都建好的情况下 walk 就是不断查页表的过程，那么在没有页表的情况下，walk 还可以建立一个个页表。稍有不同的是，walk 返回的是最后一级页表项的地址，我们需要将物理地址写入这个页表项中。</p>
<p>在 uCore 中使用 mappages 函数封装了 walk 函数，具体如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define PA2PTE(pa) ((((uint64)pa) &gt;&gt; 12) &lt;&lt; 10)
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cm">/**
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 为从虚拟地址 va 开始的页面创建指向物理地址 pa 开始的页表项（PTE）
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 注意：va 和 size 可能不是页面对齐的
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 如果无法分配所需的页表，则返回 0，否则返回 -1
</span></span></span><span class="line"><span class="cl"><span class="cm"> * 
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param pagetable 根页表地址
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param va        虚拟地址
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param size      映射的字节数
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param pa        物理地址
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @param perm      权限位
</span></span></span><span class="line"><span class="cl"><span class="cm"> * @return          成功返回 0，否则返回 -1
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">mappages</span><span class="p">(</span><span class="kt">pagetable_t</span> <span class="n">pagetable</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">va</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">size</span><span class="p">,</span> <span class="n">uint64</span> <span class="n">pa</span><span class="p">,</span> <span class="kt">int</span> <span class="n">perm</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">uint64</span> <span class="n">virtualAddress</span><span class="p">,</span> <span class="n">lastVirtualAddress</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kt">pte_t</span> <span class="o">*</span><span class="n">pte</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// 地址必须是页面对齐的
</span></span></span><span class="line"><span class="cl">    <span class="n">virtualAddress</span>     <span class="o">=</span> <span class="nf">PGROUNDDOWN</span><span class="p">(</span><span class="n">va</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">lastVirtualAddress</span> <span class="o">=</span> <span class="nf">PGROUNDDOWN</span><span class="p">(</span><span class="n">va</span> <span class="o">+</span> <span class="n">size</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 返回最低级的虚拟地址的页表项，如果不存在会创建一个新的页表项
</span></span></span><span class="line"><span class="cl">        <span class="c1">// 页表项可能会因为内存不足创建失败，如果创建失败，则返回 -1
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">((</span><span class="n">pte</span> <span class="o">=</span> <span class="nf">walk</span><span class="p">(</span><span class="n">pagetable</span><span class="p">,</span> <span class="n">virtualAddress</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 如果 PTE 已经有效，则输出错误信息并返回 -1
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">pte</span> <span class="o">&amp;</span> <span class="n">PTE_V</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nf">errorf</span><span class="p">(</span><span class="s">&#34;remap&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 将物理地址 pa 转换为页表项，并设置权限位 perm 和 有效位 PTE_V
</span></span></span><span class="line"><span class="cl">        <span class="o">*</span><span class="n">pte</span> <span class="o">=</span> <span class="nf">PA2PTE</span><span class="p">(</span><span class="n">pa</span><span class="p">)</span> <span class="o">|</span> <span class="n">perm</span> <span class="o">|</span> <span class="n">PTE_V</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 如果当前是最后一个地址，则结束循环
</span></span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">virtualAddress</span> <span class="o">==</span> <span class="n">lastVirtualAddress</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">virtualAddress</span> <span class="o">+=</span> <span class="n">PGSIZE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">pa</span> <span class="o">+=</span> <span class="n">PGSIZE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h1 id="问答作业">问答作业</h1>
<h2 id="请列举-sv39-页表页表项的组成结合课堂内容描述其中的标志位有何作用潜在作用">请列举 SV39 页表页表项的组成，结合课堂内容，描述其中的标志位有何作用／潜在作用？</h2>
<p>Sv39 页表页表项的组成如下：</p>
<ol>
<li><strong>有效位 (V)</strong>：这是页表项的最高位，用于指示页表项是否有效。如果有效位设置为 1，表示页表项有效，可以使用；如果设置为 0，表示页表项无效，禁止使用。这是虚拟内存中页表项的基本有效性标志。</li>
<li><strong>写入位 (W)</strong>：这个标志位用于指示是否可以对此页进行写入操作。如果设置为 1，表示允许写入；如果设置为 0，表示禁止写入。它是页表项的访问权限控制标志之一。</li>
<li><strong>用户位 (U)</strong>：用户位用于指示是否允许用户态程序访问此页。如果设置为 1，表示允许用户态访问；如果设置为 0，表示只允许内核态访问。它是页表项的访问权限控制标志之一。</li>
<li><strong>执行位 (X)</strong>：执行位用于指示是否允许执行此页上的指令。如果设置为 1，表示允许执行；如果设置为 0，表示禁止执行。它也是页表项的访问权限控制标志之一。</li>
<li><strong>全局位 (G)</strong>：全局位用于指示此页是否是全局的，即无需 TLB 缓存，通常用于内核页。如果设置为 1，表示是全局的；如果设置为 0，表示不是全局的。</li>
<li><strong>已访问位 (A)</strong>：已访问位表示是否已经访问过此页，通常由硬件设置。操作系统可以用它来实现页面置换算法，如 LRU。</li>
<li><strong>已修改位 (D)</strong>：已修改位表示是否已经对此页进行了写入操作。与已访问位类似，操作系统可以用它来实现页面置换算法。</li>
<li><strong>物理页框地址 (PPN)</strong>：这是页表项中存储的物理页框的地址。它指示了虚拟页到物理页的映射关系。</li>
</ol>
<p>Sv39 页表的页表项标志位允许操作系统和硬件实现对虚拟内存的细粒度控制和保护。不同的标志位组合可以实现不同级别的内存保护和权限控制，从而提高系统的安全性和可用性。例如，有效位、写入位、用户位和执行位的不同组合可以实现不同级别的内存保护，使操作系统可以将不同的内存区域分配给用户态和内核态，并设置不同的权限。已访问位和已修改位则用于实现页面置换算法，帮助操作系统决定哪些页面应该被置换出去，以优化内存利用率。全局位可以用于标识全局共享的页，从而节省 TLB 缓存空间。物理页框地址是页表项的核心，它建立了虚拟地址到物理地址的映射关系，使虚拟内存管理成为可能。</p>
<h2 id="缺页相关问题">缺页相关问题</h2>
<h3 id="请问哪些异常可能是缺页导致的">请问哪些异常可能是缺页导致的？</h3>
<p>缺页异常是由于进程访问的页面不在页表中或者在页表中无效而引发的异常。以下这些异常可能是因为缺页导致的：</p>
<ul>
<li>
<p>Load Page Fault（Load 异常）：当进程试图读取一个不在页表中或者无效的页面时，会引发 Load Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 5。</p>
</li>
<li>
<p>Store Page Fault（Store 异常）：当进程试图写入一个不在页表中或者无效的页面时，会引发 Store Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 7。</p>
</li>
<li>
<p>Instruction Page Fault（指令页异常）：当进程试图执行一个不在页表中或者无效的页面上的指令时，会引发 Instruction Page Fault 异常。在 RISC-V 中，这个异常对应的异常代码是 12。</p>
</li>
</ul>
<h3 id="发生缺页时描述相关的重要寄存器的值lab2-中描述过的可以简单点">发生缺页时，描述相关的重要寄存器的值（lab2 中描述过的可以简单点）。</h3>
<ul>
<li>sepc（Exception Program Counter）：trap 发生时会将当前指令的下一条指令地址写入其中，用于 trap 处理完成后返回。</li>
<li>stval（Machine Trap Value）：mtval 寄存器包含导致异常的原因，即导致异常的指令的具体信息。例如，如果是缺页异常，那么 mtval 寄存器包含导致缺页异常的虚拟地址。</li>
<li>scause: 中断/异常发生时， CSR 寄存器 scause 中会记录其信息， Interrupt 位记录是中断还是异常， Exception Code 记录中断/异常的种类。</li>
<li>sstatus: 记录处理器当前状态，其中 SPP 段记录当前特权等级。</li>
<li>stvec: 记录处理 trap 的入口地址，现有两种模式  Direct 和 Vectored 。</li>
<li>sscratch: 其中的值是指向hart相关的S态上下文的指针，比如内核栈的指针。</li>
</ul>
<h3 id="以下行为的好处">以下行为的好处？</h3>
<p>缺页有两个常见的原因，其一是 Lazy 策略，也就是直到内存页面被访问才实际进行页表操作。比如，一个程序被执行时，进程的代码段理论上需要从磁盘加载到内存。但是 os 并不会马上这样做，而是会保存 .text 段在磁盘的位置信息，在这些代码第一次被执行时才完成从磁盘的加载操作。</p>
<p>Lazy Loading 策略有以下好处：</p>
<ol>
<li><strong>减少初始化开销</strong>：Lazy Loading 允许操作系统在程序启动时只加载必需的页面，而不是一次性加载整个程序。这可以减少启动时间和初始化开销，因为不需要将整个程序加载到内存中。</li>
<li><strong>节省内存</strong>：Lazy Loading 策略避免了不必要的内存占用。如果程序的某些部分从不被访问，那么它们就不会被加载到内存中，从而节省了内存资源。</li>
<li><strong>提高响应速度</strong>：通过仅在需要时加载页面，Lazy Loading 可以提高系统的响应速度。只有当程序访问某个页面时，操作系统才会执行磁盘加载操作，而不会在程序启动时浪费时间加载可能永远不会被访问的内容。</li>
<li><strong>更好的磁盘利用率</strong>：Lazy Loading 允许操作系统将程序的不同部分分散在磁盘上，根据需要加载。这可以提高磁盘利用率，因为不需要在磁盘上为整个程序分配连续的空间。</li>
</ol>
<h3 id="请问处理-10g-连续的内存页面需要操作的页表实际大致占用多少内存-给出数量级即可">请问处理 10G 连续的内存页面，需要操作的页表实际大致占用多少内存 (给出数量级即可)？</h3>
<blockquote>
<p>此外 COW(Copy On Write) 也是常见的容易导致缺页的 Lazy 策略，这个之后再说。其实，我们的 mmap 也可以采取 Lazy 策略，比如：一个用户进程先后申请了 10G 的内存空间，然后用了其中 1M 就直接退出了。按照现在的做法，我们显然亏大了，进行了很多没有意义的页表操作。</p>
</blockquote>
<p>处理 10GB 连续的内存页面所需的页表实际上占用的内存量取决于操作系统的页表结构和管理策略。在 RISC-V 的页表结构中，一个页表项（Page Table Entry，PTE）通常占据 8 字节（64 位系统），其中包括物理页框号和一些标志位。让我们假设一个 PTE 占用 8 字节。</p>
<p>为了估算 10GB 连续内存页面所需的页表实际占用内存量，我们可以按照以下步骤进行计算：</p>
<ol>
<li>
<p>首先，将 10GB 转换为字节数。1GB 等于 1,073,741,824 字节，所以 10GB 等于 10 * 1,073,741,824 = 10,737,418,240 字节。</p>
</li>
<li>
<p>然后，计算每个页面表项覆盖的内存范围。假设每个页面表项管理 4KB（4 * 1024 字节）的内存页面。</p>
</li>
<li>
<p>计算需要多少个页面表项来管理 10GB 的内存。这可以通过将 10GB 除以每个页面表项管理的内存范围来实现。</p>
</li>
<li>
<p>最后，将所需的页面表项数量乘以每个 PTE 的大小来估算所需的总内存量。</p>
</li>
</ol>
<p>让我们进行具体计算：</p>
<ul>
<li>内存大小：10,737,418,240 字节</li>
<li>每个页面表项管理的内存范围：4KB = 4 * 1024 字节</li>
<li>需要的页面表项数量：10,737,418,240 字节 / 4KB = 2,621,440 个页表项</li>
</ul>
<p>假设每个页表项占用 8 字节，则需要的总内存量为：</p>
<p>2,621,440 个页表项 * 8 字节/页表项 = 20,971,520 字节</p>
<p>所以，处理 10GB 连续的内存页面所需的页表实际占用内存量约为 20,971,520 字节，或者大约 20MB。这只是一个估算，实际内存占用可能会因操作系统的管理策略和对齐等因素而有所不同。</p>
<h3 id="请简单思考如何才能在现有框架基础上实现-lazy-策略缺页时又如何处理描述合理即可不需要考虑实现">请简单思考如何才能在现有框架基础上实现 Lazy 策略，缺页时又如何处理？描述合理即可，不需要考虑实现。</h3>
<p>要在现有框架基础上实现 Lazy 策略，可以采取以下简单思路：</p>
<ol>
<li>
<p><strong>延迟加载（Lazy Loading）</strong>：在用户进程请求内存映射时，不立即将整个内存区域加载到物理内存中。而是仅创建虚拟内存映射和页表项，记录对应的磁盘位置等信息。</p>
</li>
<li>
<p><strong>缺页处理（Page Fault Handling）</strong>：当用户进程访问虚拟内存中的某个尚未加载的内存页面时，会触发缺页异常。在缺页异常处理程序中，操作系统会根据页表中的磁盘位置信息，将相应的磁盘数据加载到物理内存中，并更新页表项，使其指向新加载的物理页面。</p>
</li>
<li>
<p><strong>惰性加载（Demand Paging）</strong>：为了提高性能，可以采用惰性加载策略，即只加载实际被访问的内存页面，而不是一次性加载整个区域。这可以通过在缺页处理程序中进行懒加载操作来实现。</p>
</li>
<li>
<p><strong>内存回收（Memory Reclamation）</strong>：当系统内存不足时，操作系统可以选择回收一些不常访问的内存页面，将其写回磁盘，并更新页表项为无效。这需要根据页面访问模式和策略来确定哪些页面可以被回收。</p>
</li>
<li>
<p><strong>性能优化</strong>：为了提高性能，可以采用预读取（Prefetching）策略，即在缺页处理时，不仅加载当前访问的页面，还预先加载相邻的页面，以减少未来可能的缺页次数。</p>
</li>
</ol>
<h3 id="此时页面失效如何表现在页表项-pte-上">此时页面失效如何表现在页表项 (PTE) 上？</h3>
<blockquote>
<p>缺页的另一个常见原因是 swap 策略，也就是内存页面可能被换到磁盘上了，导致对应页面失效。</p>
</blockquote>
<p>Dirty bit (D 位)：当页面被修改并且尚未写回到主存时，该位会被设置为 1。如果页面已经被换出到磁盘上，D 位将保持为 1，以指示页面数据已过期。</p>
<p>Valid bit (V 位)：当页面在主存中有效时，V 位被设置为 1。如果页面被换出到磁盘上，V 位将被清除为 0，表示该页无效。</p>
<p>通过检查页表项的 D 位和 V 位，操作系统可以确定页面是否需要从磁盘重新加载到内存中。如果 D 位为 1，说明页面需要写回到主存，在将其置为有效之前，必须将页数据从磁盘读取到内存中。如果 V 位为 0，说明页面当前无效，需要将其从磁盘加载到内存中，并将 V 位设置为 1，表示页面有效。</p>
<h2 id="双页表与单页表">双页表与单页表</h2>
<p>为了防范侧信道攻击，我们的 os 使用了双页表。但是传统的设计一直是单页表的，也就是说，用户线程和对应的内核线程共用同一张页表，只不过内核对应的地址只允许在内核态访问。请结合课堂知识回答如下问题：(备注：这里的单/双的说法仅为自创的通俗说法，并无这个名词概念，详情见 KPTI )</p>
<h2 id="单页表情况下如何更换页表">单页表情况下，如何更换页表？</h2>
<p>在单页表情况下，页表的更换通常是由操作系统的上下文切换来触发的。当从用户态切换到内核态或从一个进程切换到另一个进程时，操作系统会根据相应的上下文信息加载不同的页表，实现页表的更换。</p>
<h2 id="单页表情况下如何控制用户态无法访问内核页面tips看看第一题最后一问">单页表情况下，如何控制用户态无法访问内核页面？（tips:看看第一题最后一问）</h2>
<ul>
<li>设置页面权限：内核页面通常会被设置为只能在内核态下访问（例如，设置 PTE_U 位为 0），这样用户态无法访问内核页面。</li>
<li>操作系统权限：操作系统内核态拥有较高的权限，可以通过特权级别或访问控制机制来确保用户态无法直接访问内核页面。用户程序只能通过系统调用进入内核态，并在内核态下由操作系统执行，从而实现对内核页面的访问控制。</li>
</ul>
<h2 id="单页表有何优势回答合理即可">单页表有何优势？（回答合理即可）</h2>
<p>单页表的主要优势在于简化了地址转换过程，减少了内存访问的开销。由于用户线程和内核线程共享同一张页表，不需要在上下文切换时频繁切换页表，这可以提高地址转换的效率。此外，单页表还可以节省内存，因为不需要为每个用户线程分配独立的页表。</p>
<h2 id="双页表实现下何时需要更换页表假设你写一个单页表操作系统你会选择何时更换页表回答合理即可">双页表实现下，何时需要更换页表？假设你写一个单页表操作系统，你会选择何时更换页表（回答合理即可）？</h2>
<p>在双页表实现下，页表的更换通常在发生上下文切换时需要。当从用户态切换到内核态或从一个进程切换到另一个进程时，需要加载相应的页表，以确保正确的地址转换。如果操作系统采用了每个进程独立的页表，那么在进程切换时需要更换页表。</p>
<p>如果我写一个单页表操作系统，我会选择在发生进程切换时更换页表，因为这是最频繁的上下文切换情况之一。在其他情况下，如从用户态切换到内核态，可能不需要更换整张页表，而只需修改页表项的权限位来实现访问控制。这样可以减少页表更换的开销，提高性能。</p>
<h1 id="附录">附录</h1>
<p>修改user项目中的makefile，删除ch4_</p>
]]></content:encoded>
    </item>
    <item>
      <title>uCore 实验第 3 章 - 多道程序与分时多任务</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC3%E7%AB%A0-%E5%A4%9A%E9%81%93%E7%A8%8B%E5%BA%8F%E4%B8%8E%E5%88%86%E6%97%B6%E5%A4%9A%E4%BB%BB%E5%8A%A1/</link>
      <pubDate>Sat, 02 Sep 2023 16:03:02 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC3%E7%AB%A0-%E5%A4%9A%E9%81%93%E7%A8%8B%E5%BA%8F%E4%B8%8E%E5%88%86%E6%97%B6%E5%A4%9A%E4%BB%BB%E5%8A%A1/</guid>
      <description>&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 启动时初始化进程表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UNUSED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// p - pool 是 p 指向的 proc 在 pool 中的下标，因此 p - pool 变化情况是 0, 1, 2, ..., NPROC - 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;		* LAB1: you may need to initialize your new fields of proc here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;		*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;boot_stack_top&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;current_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;p - pool 表示什么？
假设我们有一个名为 pool 的数组，其中包含了多个类型为 struct proc 的元素，并且有一个指针 p 指向其中的某个元素。
当 p 指向 pool 数组的第一个元素时，p - pool 的结果将是 0，因为指针相对于数组首地址的偏移量为 0。
当 p 指向 pool 数组的第二个元素时，p - pool 的结果将是 1，因为指针相对于数组首地址的偏移量为 1。
以此类推，当 p 指向 pool 数组的第 N 个元素时，p - pool 的结果将是 N-1，因为指针相对于数组首地址的偏移量为 N-1。
总结来说，如果 p 是指向 pool 数组中第 N 个元素的指针，那么 p - pool 的结果将是 N-1。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原调度函数每次都会从 pool 数组的第一个元素开始遍历，这样会导致每次都是从第一个进程开始运行，而不是从上次运行的进程开始运行。需要修改为如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 调度程序永不返回。它循环执行以下操作：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//  - 选择要运行的进程。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//  - 切换以启动运行该进程。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//  - 最终，该进程通过切换将控制权
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//    传递回调度程序。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;scheduler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 初始化指针为 pool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 p 初始化为 last_checked_proc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;                * LAB1：你可能需要在这里初始化进程的起始时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;                */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;n&#34;&gt;current_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nf&#34;&gt;swtch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 更新 last_checked_proc 的值为下一个位置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;lab1&#34;&gt;LAB1&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;           &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;             &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;             &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;23&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;          &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;55&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;++++-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;      &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;            &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;files&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;changed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;374&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;insertions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;291&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;deletions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b45e85d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;b21b0a4&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;loader.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;defs.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;trap.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;app_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app_info_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;49&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;50&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;run_all_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sp&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;USER_STACK_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;       &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-		* LAB1: you may need to initialize your new fields of proc here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+		* LAB1: 初始化系统调用数以及进程开始时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; 		*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;nf&#34;&gt;memset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;\&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;No&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;newline&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;at&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fee3886&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.0&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c69ae5&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;defs.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;loader.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;trap.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;timer.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PAGE_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;33&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;34&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;proc_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ustack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;        &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-		* LAB1: you may need to initialize your new fields of proc here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-		*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;nf&#34;&gt;memset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;boot_stack_top&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;47&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;47&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;allocpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PID&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PID&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 在进程表中寻找一个未使用的进程。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 如果找到，则初始化在内核中运行所需的状态。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// 如果没有空闲的进程，或者内存分配失败，则返回 0。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;81&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;18&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;scheduler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 初始化指针为 pool
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(;;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last_checked_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NPROC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 将 p 初始化为 last_checked_proc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-                * LAB1：你可能需要在这里初始化进程的起始时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+                * LAB1：在这里初始化进程的开始时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;                 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                    &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MILLISECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;                &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;n&#34;&gt;current_proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;nf&#34;&gt;swtch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;d208c5d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.53576&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bf&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;types.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;NPROC&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;NPROC&lt;/span&gt;           &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 最大进程数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;500&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 最大系统调用数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// Saved registers for kernel context switches.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;42&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;43&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;28&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt;            &lt;span class=&#34;n&#34;&gt;kstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 进程内核栈虚拟地址 (内核页表)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;trapframe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 进程中断帧
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 用于保存进程内核态的寄存器信息，进程切换时使用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;                               &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-	* LAB1: you may need to add some new fields here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+    /*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+	* LAB1: 添加一些新的成员用于新的 sys_task_info 系统调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; 	*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 系统调用次数统计 TODO: 后续改为指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 进程开始运行时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-* LAB1: you may need to define struct for TaskInfo here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+* LAB1: 定义 TaskInfo 结构体
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;UnInit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;Ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;Running&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;Exited&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TaskStatus&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;TaskStatus&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint32&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 进程运行时间统计
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TaskInfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;curr_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;         &lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cc5aeb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f54ed86&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;syscall_ids.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;timer.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;#34;trap.h&amp;#34;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;proc.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;32&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;46&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_sched_yield&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_gettimeofday&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TimeVal&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_tz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sec&lt;/span&gt;     &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usec&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MICROSECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;tracef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sys_gettimeofday cycle = %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sec&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;msec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MILLISECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;usec&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MICROSECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-* LAB1: you may need to define sys_task_info here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/** 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+ * LAB1：此处定义 sys_task_info 函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+ * 查询当前正在执行的任务信息，任务信息包括任务控制块相关信息（任务状态）、任务使用的系统调用次数、任务总运行时长。 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+ */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_task_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TaskInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;curr_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// TODO: proc 检查为空
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MAX_SYSCALL_NUM&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cycle&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MILLISECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CPU_FREQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;infof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sys_task_info current_time = %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;infof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;proc-&amp;gt;start_time = %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;infof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;ti-&amp;gt;time = %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Running&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RUNNABLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SLEEPING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Ready&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ZOMBIE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Exited&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UNUSED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;UnInit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;ti&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_time&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;proc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;trap_page&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;51&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;nf&#34;&gt;tracef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;syscall %d args = [%x, %x, %x, %x, %x, %x]&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-	* LAB1: you may need to update syscall counter for task info here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+	* LAB1: 更新系统调用次数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; 	*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;curr_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_times&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SYS_write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;67&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;101&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;syscall&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_gettimeofday&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TimeVal&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-	* LAB1: you may need to add SYS_taskinfo case here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;+	* LAB1: 在此处添加 SYS_task_info 的系统调用处理情况
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt; 	*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SYS_task_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;sys_task_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;TaskInfo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;SYS_getpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;nf&#34;&gt;infof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;SYS_getpid %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SYS_getpid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;curr_proc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;ret&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;nf&#34;&gt;errorf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;unknown syscall %d&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;05&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a6cb9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.3&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c1a5a9&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syscall_ids&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;277&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;277&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_io_pgetevents          292
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_rseq                   293
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_kexec_file_load        294
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-* LAB1: you may need to define SYS_task_info here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;-*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// LAB1：添加 SYS_task_info 的系统调用号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SYS_task_info&lt;/span&gt;          &lt;span class=&#34;mi&#34;&gt;410&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_pidfd_send_signal  424
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_io_uring_setup     425
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define SYS_io_uring_enter     426
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;diff&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;c6ebd14&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;.63&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ab45c&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;100644&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+++&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;b&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define TICKS_PER_SEC (100)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;c1&#34;&gt;// QEMU
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define CPU_FREQ                (12500000)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;MILLISECONDS_PER_SECOND&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cp&#34;&gt;#define MICROSECONDS_PER_SECOND (1000000)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_cycle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;@@&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;   &lt;span class=&#34;nf&#34;&gt;set_next_timer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 自 Unix 纪元起的秒数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;msec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 毫秒数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;     &lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;usec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 微秒数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TimeVal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mf&#34;&gt;2.34.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;问答作业&#34;&gt;问答作业&lt;/h1&gt;
&lt;h2 id=&#34;问题一&#34;&gt;问题一&lt;/h2&gt;
&lt;p&gt;正确进入 U 态后，程序的特征还应有：使用 S 态特权指令，访问 S 态寄存器后会报错。请同学们可以自行测试这些内容（参考 前三个测例，描述程序出错行为，同时注意注明你使用的 sbi 及其版本。&lt;/p&gt;
&lt;p&gt;测试前三个测试用例指的是&lt;code&gt;uCore-Tutorial-Code-2023S/user/src/&lt;/code&gt; 目录下的三个&lt;code&gt;bad&lt;/code&gt;测试用例，查看&lt;code&gt;user&lt;/code&gt;项目的 Makefile 可以发现在编译时修改&lt;code&gt;CHAPTER&lt;/code&gt;参数值为&lt;code&gt;2_bad&lt;/code&gt;即可编译运行这些测试用例。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; RustSBI version 0.3.0-alpha.2, adapting to RISC-V SBI v1.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.______       __    __      _______.___________.  _______..______   __
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   _  &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    /       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;           &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; /       &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;   _  &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;----&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;---&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;----&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;----&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      /     &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;    &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;  &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;  &lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   _  &amp;lt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\ &lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\-&lt;/span&gt;---.&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;--&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;.----&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  .----&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;   &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; _&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;._____&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\_&lt;/span&gt;_____/ &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_______/       &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;__&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;_______/    &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;______/ &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;__&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Implementation     : RustSBI-QEMU Version 0.2.0-alpha.2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Platform Name      : riscv-virtio,qemu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Platform SMP       : &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Platform Memory    : 0x80000000..0x88000000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Boot HART          : &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Device Tree Region : 0x87000000..0x87000ef2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Firmware Address   : 0x80000000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; Supervisor Address : 0x80200000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; pmp01: 0x00000000..0x80000000 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;-wr&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; pmp02: 0x80000000..0x80200000 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;---&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; pmp03: 0x80200000..0x88000000 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;xwr&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;rustsbi&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; pmp04: 0x88000000..0x00000000 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;-wr&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;TRACE 0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;load app &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; at 0x0000000080400000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;TRACE 0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;load app &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; at 0x0000000080420000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;TRACE 0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;load app &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; at 0x0000000080440000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO 0&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;start scheduler!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;ERROR 1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;unknown trap: 0x0000000000000007, &lt;span class=&#34;nv&#34;&gt;stval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; 0x0000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO 1&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;进程 &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 以代码 -1 退出
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IllegalInstruction in application, core dumped.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO 2&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;进程 &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; 以代码 -3 退出
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IllegalInstruction in application, core dumped.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;INFO 3&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;进程 &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; 以代码 -3 退出
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;PANIC 3&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; os/loader.c:15: all apps over
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个进程测试用例如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在您提供的代码中，将空指针分配给指针变量*p 后，试图对其进行解引用并将值 0 赋给该指针。由于用户模式下禁止直接访问物理内存，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped.&lt;/p&gt;
&lt;p&gt;在 RISC-V 架构中，U 模式是最低的用户模式，用户程序无法直接访问物理内存或其他特权级别资源。这种限制是为了确保操作系统的安全性和稳定性。&lt;/p&gt;
&lt;p&gt;第二个进程测试用例如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;volatile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;sret&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;试图使用汇编语言执行 sret 指令，该指令用于从中断或异常处理程序返回。由于用户模式下禁止直接访问特权级别寄存器，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped。&lt;/p&gt;
&lt;p&gt;第三个进程测试用例如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;asm&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;volatile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;csrr %0, sstatus&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原因同上，试图使用汇编语言执行 csrr 指令，该指令用于从特权级别寄存器中读取值。由于用户模式下禁止直接访问特权级别寄存器，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped。&lt;/p&gt;
&lt;p&gt;在操作系统代码中，触发异常后会进入&lt;code&gt;void usertrap()&lt;/code&gt; 函数，该函数会根据 &lt;code&gt;scause&lt;/code&gt; 寄存器的值判断异常类型，用例中的结果进入了&lt;code&gt;case IllegalInstruction&lt;/code&gt;，其中 &lt;code&gt;IllegalInstruction = 2&lt;/code&gt;。我们查阅手册 &lt;code&gt;riscv-privileged.pdf&lt;/code&gt; ，可以查到 &lt;code&gt;IllegalInstruction&lt;/code&gt; 的值为 2，与预期相符。&lt;/p&gt;
&lt;h2 id=&#34;问题二&#34;&gt;问题二&lt;/h2&gt;
&lt;p&gt;请结合用例理解 trampoline.S 中两个函数 &lt;code&gt;userret&lt;/code&gt; 和 &lt;code&gt;uservec&lt;/code&gt; 的作用，并回答如下几个问题：&lt;/p&gt;
&lt;h3 id=&#34;l79-刚进入-userret-时a0a1-分别代表了什么值&#34;&gt;L79: 刚进入 &lt;code&gt;userret&lt;/code&gt; 时，&lt;code&gt;a0&lt;/code&gt;、&lt;code&gt;a1&lt;/code&gt; 分别代表了什么值。&lt;/h3&gt;
&lt;p&gt;在进入&lt;code&gt;userret&lt;/code&gt;函数时，&lt;code&gt;a0&lt;/code&gt;和&lt;code&gt;a1&lt;/code&gt;分别代表以下值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;a0&lt;/code&gt;: TRAPFRAME 的地址，指向当前进程的陷阱帧（trapframe）结构体。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a1&lt;/code&gt;: 用户页表的地址，即进程的页表（pagetable）。这个地址会被写入到&lt;code&gt;satp&lt;/code&gt;寄存器中，用于切换到用户模式的页表。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;l87-l88-sfence-指令有何作用为什么要执行该指令当前章节中删掉该指令会导致错误吗&#34;&gt;L87-L88: &lt;code&gt;sfence&lt;/code&gt; 指令有何作用？为什么要执行该指令，当前章节中，删掉该指令会导致错误吗？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;csrw&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;satp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;a1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;sfence.vma&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;zero&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;sfence&lt;/code&gt;指令（Store Fence）的作用是确保之前的存储操作完成，并且对其他处理器上的核心可见。&lt;/p&gt;
&lt;p&gt;执行&lt;code&gt;sfence&lt;/code&gt;指令的主要目的是为了保证内存访问的顺序性和一致性。在多核处理器系统中，不同的核心可能会有自己的缓存，当一个核心修改了共享内存中的数据时，为了保证其他核心能够看到这个修改，需要使用&lt;code&gt;sfence&lt;/code&gt;指令来刷新缓存并将修改写回共享内存。&lt;/p&gt;
&lt;p&gt;在代码中，&lt;code&gt;sfence&lt;/code&gt;指令被用于确保对用户页表的修改对其他处理器上的核心可见。因为目前我只使用了单核处理器，所以不会出现多核处理器的情况，因此&lt;code&gt;sfence&lt;/code&gt;指令的作用是确保对用户页表的修改对当前核心可见。&lt;/p&gt;
&lt;p&gt;因此，当前章节中，&lt;strong&gt;删掉该指令不会导致错误&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;l96-l125-为何注释中说要除去-a0哪一个地址代表-a0现在-a0-的值存在何处&#34;&gt;L96-L125: 为何注释中说要除去 &lt;code&gt;a0&lt;/code&gt;？哪一个地址代表 &lt;code&gt;a0&lt;/code&gt;？现在 &lt;code&gt;a0&lt;/code&gt; 的值存在何处？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;# restore all but a0 from TRAPFRAME
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld ra, 40(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld sp, 48(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld t5, 272(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld t6, 280(a0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;a0&lt;/code&gt; 是&lt;strong&gt;保存在 &lt;code&gt;sscratch&lt;/code&gt; 寄存器中的&lt;/strong&gt;，首先，该代码通过 &lt;code&gt;ld&lt;/code&gt; 指令从 &lt;code&gt;TRAPFRAME&lt;/code&gt; 中加载各个寄存器的值。然后，这些值被存储在相应的寄存器中，以便在恢复用户上下文时使用。&lt;/p&gt;
&lt;p&gt;接下来，代码使用 &lt;code&gt;csrrw&lt;/code&gt; 指令将 sscratch 寄存器的值与 &lt;code&gt;a0&lt;/code&gt;（即 &lt;code&gt;TRAPFRAME&lt;/code&gt;）进行交换。这样做是为了将用户的 &lt;code&gt;a0&lt;/code&gt;（&lt;code&gt;TRAPFRAME&lt;/code&gt;）保存在 &lt;code&gt;sscratch&lt;/code&gt; 寄存器中，以便后续步骤可以正确地恢复用户上下文。&lt;/p&gt;
&lt;p&gt;最后，通过 &lt;code&gt;sret&lt;/code&gt; 指令返回到用户模式，并将控制权交给用户代码。在执行 &lt;code&gt;sret&lt;/code&gt; 指令后，处理器将根据用户上下文中的 &lt;code&gt;sepc&lt;/code&gt; 寄存器的值跳转到用户代码的指令地址。返回的同时，处理器还会自动恢复 &lt;code&gt;sstatus&lt;/code&gt; 寄存器的值，以确保正确的特权级别和中断状态。&lt;/p&gt;
&lt;h3 id=&#34;userret中发生状态切换在哪一条指令为何执行之后会进入用户态&#34;&gt;&lt;code&gt;userret&lt;/code&gt;：中发生状态切换在哪一条指令？为何执行之后会进入用户态？&lt;/h3&gt;
&lt;p&gt;在&lt;code&gt;userret&lt;/code&gt;函数中，发生状态切换的指令是&lt;code&gt;sret&lt;/code&gt;指令。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sret&lt;/code&gt;指令用于从内核模式切换到用户模式，并将控制权交给用户代码。执行&lt;code&gt;sret&lt;/code&gt;指令后，处理器会根据用户上下文中的&lt;code&gt;sepc&lt;/code&gt;寄存器的值跳转到用户代码的指令地址。&lt;/p&gt;
&lt;p&gt;执行&lt;code&gt;sret&lt;/code&gt;指令之后进入用户态的原因是，该指令会自动恢复&lt;code&gt;sstatus&lt;/code&gt;寄存器的值，以确保正确的特权级别和中断状态。当&lt;code&gt;sret&lt;/code&gt;指令执行后，处理器将从内核态切换回用户态，程序将继续执行用户代码。这意味着&lt;code&gt;userret&lt;/code&gt;函数成功完成了从内核切换到用户模式的过程。&lt;/p&gt;
&lt;h3 id=&#34;l29执行之后a0-和-sscratch-中各是什么值为什么&#34;&gt;L29：执行之后，a0 和 sscratch 中各是什么值，为什么？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;csrrw a0, sscratch, a0     
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在执行指令后，&lt;code&gt;a0&lt;/code&gt;和&lt;code&gt;sscratch&lt;/code&gt;中的值发生了互换。&lt;/p&gt;
&lt;p&gt;假设原始&lt;code&gt;a0&lt;/code&gt;寄存器中的值为 X，而&lt;code&gt;sscratch&lt;/code&gt;寄存器中的值为 Y。执行&lt;code&gt;csrrw a0, sscratch, a0&lt;/code&gt;指令后，&lt;code&gt;a0&lt;/code&gt;寄存器中的值变为 Y，而&lt;code&gt;sscratch&lt;/code&gt;寄存器中的值变为 X。&lt;/p&gt;
&lt;p&gt;这是因为&lt;code&gt;csrrw&lt;/code&gt;指令是一个特权指令，用于将某个 CSR（Control and Status Register）的值读取到目标寄存器，然后将目标寄存器的值写回到该 CSR 中。在这里，&lt;code&gt;csrrw a0, sscratch, a0&lt;/code&gt;指令将&lt;code&gt;sscratch&lt;/code&gt;寄存器的值读取到&lt;code&gt;a0&lt;/code&gt;寄存器中，同时将&lt;code&gt;a0&lt;/code&gt;寄存器中的值写回到&lt;code&gt;sscratch&lt;/code&gt;寄存器中，从而实现了两者之间的数据交换。&lt;/p&gt;
&lt;h3 id=&#34;l32-l61-从-trapframe-第几项开始保存为什么是否从该项开始保存了所有的值如果不是为什么&#34;&gt;L32-L61: 从 trapframe 第几项开始保存？为什么？是否从该项开始保存了所有的值，如果不是，为什么？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sd ra, 40(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sd sp, 48(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sd t5, 272(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sd t6, 280(a0)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;进入-s-态是哪一条指令发生的&#34;&gt;进入 S 态是哪一条指令发生的？&lt;/h3&gt;
&lt;h3 id=&#34;l75-l76-ld-t0-16a0-执行之后t0中的值是什么解释该值的由来&#34;&gt;L75-L76: &lt;code&gt;ld t0, 16(a0)&lt;/code&gt; 执行之后，&lt;code&gt;t0&lt;/code&gt;中的值是什么，解释该值的由来？&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ld t0, 16(a0)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;jr t0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ld t0, 16(a0)&lt;/code&gt;就是从 &lt;code&gt;trapframe&lt;/code&gt; 中恢复 &lt;code&gt;t0&lt;/code&gt;寄存器值，&lt;code&gt;t0&lt;/code&gt;保存了&lt;code&gt;kernel_trap&lt;/code&gt;的入口地址。使用 &lt;code&gt;jr t0&lt;/code&gt;，就跳转到了我们早先设定在 &lt;code&gt;trapframe-&amp;gt;kernel_trap&lt;/code&gt; 中的地址，也就是 &lt;code&gt;trap.c&lt;/code&gt; 之中的 &lt;code&gt;usertrap&lt;/code&gt; 函数。这个函数在 &lt;code&gt;main&lt;/code&gt; 的初始化之中已经调用了。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 启动时初始化进程表
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">proc_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(</span><span class="n">p</span> <span class="o">=</span> <span class="n">pool</span><span class="p">;</span> <span class="n">p</span> <span class="o">&lt;</span> <span class="o">&amp;</span><span class="n">pool</span><span class="p">[</span><span class="n">NPROC</span><span class="p">];</span> <span class="n">p</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">=</span> <span class="n">UNUSED</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// p - pool 是 p 指向的 proc 在 pool 中的下标，因此 p - pool 变化情况是 0, 1, 2, ..., NPROC - 1
</span></span></span><span class="line"><span class="cl">        <span class="n">p</span><span class="o">-&gt;</span><span class="n">kstack</span>    <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">kstack</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span><span class="o">-&gt;</span><span class="n">ustack</span>    <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">ustack</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span><span class="o">-&gt;</span><span class="n">trapframe</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">trapframe</span> <span class="o">*</span><span class="p">)</span><span class="n">trapframe</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">		* LAB1: you may need to initialize your new fields of proc here
</span></span></span><span class="line"><span class="cl"><span class="cm">		*/</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">idle</span><span class="p">.</span><span class="n">kstack</span>  <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">boot_stack_top</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">idle</span><span class="p">.</span><span class="n">pid</span>     <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">current_proc</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">idle</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><blockquote>
<p>p - pool 表示什么？
假设我们有一个名为 pool 的数组，其中包含了多个类型为 struct proc 的元素，并且有一个指针 p 指向其中的某个元素。
当 p 指向 pool 数组的第一个元素时，p - pool 的结果将是 0，因为指针相对于数组首地址的偏移量为 0。
当 p 指向 pool 数组的第二个元素时，p - pool 的结果将是 1，因为指针相对于数组首地址的偏移量为 1。
以此类推，当 p 指向 pool 数组的第 N 个元素时，p - pool 的结果将是 N-1，因为指针相对于数组首地址的偏移量为 N-1。
总结来说，如果 p 是指向 pool 数组中第 N 个元素的指针，那么 p - pool 的结果将是 N-1。</p>
</blockquote>
<p>原调度函数每次都会从 pool 数组的第一个元素开始遍历，这样会导致每次都是从第一个进程开始运行，而不是从上次运行的进程开始运行。需要修改为如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 调度程序永不返回。它循环执行以下操作：
</span></span></span><span class="line"><span class="cl"><span class="c1">//  - 选择要运行的进程。
</span></span></span><span class="line"><span class="cl"><span class="c1">//  - 切换以启动运行该进程。
</span></span></span><span class="line"><span class="cl"><span class="c1">//  - 最终，该进程通过切换将控制权
</span></span></span><span class="line"><span class="cl"><span class="c1">//    传递回调度程序。
</span></span></span><span class="line"><span class="cl"><span class="kt">void</span> <span class="nf">scheduler</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">last_checked_proc</span> <span class="o">=</span> <span class="n">pool</span><span class="p">;</span> <span class="c1">// 初始化指针为 pool
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="p">(</span><span class="n">p</span> <span class="o">=</span> <span class="n">last_checked_proc</span><span class="p">;</span> <span class="n">p</span> <span class="o">&lt;</span> <span class="o">&amp;</span><span class="n">pool</span><span class="p">[</span><span class="n">NPROC</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">             <span class="n">p</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 将 p 初始化为 last_checked_proc
</span></span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">RUNNABLE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">                * LAB1：你可能需要在这里初始化进程的起始时间
</span></span></span><span class="line"><span class="cl"><span class="cm">                */</span>
</span></span><span class="line"><span class="cl">                <span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span>     <span class="o">=</span> <span class="n">RUNNING</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="n">current_proc</span> <span class="o">=</span> <span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="nf">swtch</span><span class="p">(</span><span class="o">&amp;</span><span class="n">idle</span><span class="p">.</span><span class="n">context</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">last_checked_proc</span> <span class="o">=</span> <span class="n">pool</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 更新 last_checked_proc 的值为下一个位置
</span></span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h1 id="lab1">LAB1</h1>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="o">---</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span>           <span class="o">|</span>   <span class="mi">5</span> <span class="o">+-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span>             <span class="o">|</span>  <span class="mi">15</span> <span class="o">+-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span>             <span class="o">|</span>  <span class="mi">23</span> <span class="o">+-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span>          <span class="o">|</span>  <span class="mi">55</span> <span class="o">++++-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span>      <span class="o">|</span>   <span class="mi">5</span> <span class="o">+-</span>
</span></span><span class="line"><span class="cl"> <span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span>            <span class="o">|</span>   <span class="mi">2</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl"> <span class="mi">9</span> <span class="n">files</span> <span class="n">changed</span><span class="p">,</span> <span class="mi">374</span> <span class="nf">insertions</span><span class="p">(</span><span class="o">+</span><span class="p">),</span> <span class="mi">291</span> <span class="nf">deletions</span><span class="p">(</span><span class="o">-</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="n">b45e85d</span><span class="p">..</span><span class="n">b21b0a4</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">loader</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;loader.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;defs.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;trap.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">include</span> <span class="o">&lt;</span><span class="n">string</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">uint64</span>  <span class="n">app_num</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="k">static</span> <span class="n">uint64</span> <span class="o">*</span><span class="n">app_info_ptr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">49</span><span class="p">,</span><span class="mi">8</span> <span class="o">+</span><span class="mi">50</span><span class="p">,</span><span class="mi">10</span> <span class="err">@@</span> <span class="kt">int</span> <span class="nf">run_all_app</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">         <span class="n">trapframe</span><span class="o">-&gt;</span><span class="n">sp</span>  <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">ustack</span> <span class="o">+</span> <span class="n">USER_STACK_SIZE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span>       <span class="o">=</span> <span class="n">RUNNABLE</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-		* LAB1: you may need to initialize your new fields of proc here
</span></span></span><span class="line"><span class="cl"><span class="cm">+		* LAB1: 初始化系统调用数以及进程开始时间
</span></span></span><span class="line"><span class="cl"><span class="cm"> 		*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="nf">memset</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MAX_SYSCALL_NUM</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">uint32</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">p</span><span class="o">-&gt;</span><span class="n">start_time</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="p">}</span>
</span></span><span class="line"><span class="cl">     <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="err">\</span> <span class="n">No</span> <span class="n">newline</span> <span class="n">at</span> <span class="n">end</span> <span class="n">of</span> <span class="n">file</span>
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="n">fee3886</span><span class="p">.</span><span class="mf">.0</span><span class="n">c69ae5</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">2</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;defs.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;loader.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;trap.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">include</span> <span class="s">&#34;timer.h&#34;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">proc</span> <span class="n">pool</span><span class="p">[</span><span class="n">NPROC</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"> <span class="kt">char</span>        <span class="n">kstack</span><span class="p">[</span><span class="n">NPROC</span><span class="p">][</span><span class="n">PAGE_SIZE</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">33</span><span class="p">,</span><span class="mi">9</span> <span class="o">+</span><span class="mi">34</span><span class="p">,</span><span class="mi">8</span> <span class="err">@@</span> <span class="kt">void</span> <span class="nf">proc_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="n">p</span><span class="o">-&gt;</span><span class="n">kstack</span>    <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">kstack</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">         <span class="n">p</span><span class="o">-&gt;</span><span class="n">ustack</span>    <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">ustack</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">         <span class="n">p</span><span class="o">-&gt;</span><span class="n">trapframe</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">trapframe</span> <span class="o">*</span><span class="p">)</span><span class="n">trapframe</span><span class="p">[</span><span class="n">p</span> <span class="o">-</span> <span class="n">pool</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span>        <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-		* LAB1: you may need to initialize your new fields of proc here
</span></span></span><span class="line"><span class="cl"><span class="cm">-		*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="nf">memset</span><span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MAX_SYSCALL_NUM</span> <span class="o">*</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">uint32</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">p</span><span class="o">-&gt;</span><span class="n">start_time</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="p">}</span>
</span></span><span class="line"><span class="cl">     <span class="n">idle</span><span class="p">.</span><span class="n">kstack</span>  <span class="o">=</span> <span class="p">(</span><span class="n">uint64</span><span class="p">)</span><span class="n">boot_stack_top</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="n">idle</span><span class="p">.</span><span class="n">pid</span>     <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">47</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">47</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span> <span class="kt">int</span> <span class="nf">allocpid</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">     <span class="k">static</span> <span class="kt">int</span> <span class="n">PID</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">return</span> <span class="n">PID</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// 在进程表中寻找一个未使用的进程。
</span></span></span><span class="line"><span class="cl"> <span class="c1">// 如果找到，则初始化在内核中运行所需的状态。
</span></span></span><span class="line"><span class="cl"> <span class="c1">// 如果没有空闲的进程，或者内存分配失败，则返回 0。
</span></span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">80</span><span class="p">,</span><span class="mi">14</span> <span class="o">+</span><span class="mi">81</span><span class="p">,</span><span class="mi">18</span> <span class="err">@@</span> <span class="kt">void</span> <span class="nf">scheduler</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">last_checked_proc</span> <span class="o">=</span> <span class="n">pool</span><span class="p">;</span> <span class="c1">// 初始化指针为 pool
</span></span></span><span class="line"><span class="cl"><span class="o">-</span>
</span></span><span class="line"><span class="cl">     <span class="k">for</span> <span class="p">(;;)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="k">for</span> <span class="p">(</span><span class="n">p</span> <span class="o">=</span> <span class="n">last_checked_proc</span><span class="p">;</span> <span class="n">p</span> <span class="o">&lt;</span> <span class="o">&amp;</span><span class="n">pool</span><span class="p">[</span><span class="n">NPROC</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">              <span class="n">p</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 将 p 初始化为 last_checked_proc
</span></span></span><span class="line"><span class="cl">             <span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">RUNNABLE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                 <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-                * LAB1：你可能需要在这里初始化进程的起始时间
</span></span></span><span class="line"><span class="cl"><span class="cm">+                * LAB1：在这里初始化进程的开始时间
</span></span></span><span class="line"><span class="cl"><span class="cm">                 */</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                <span class="k">if</span> <span class="p">(</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">start_time</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                    <span class="n">uint64</span> <span class="n">cycle</span> <span class="o">=</span> <span class="nf">get_cycle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                    <span class="n">p</span><span class="o">-&gt;</span><span class="n">start_time</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                        <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MILLISECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                 <span class="n">p</span><span class="o">-&gt;</span><span class="n">state</span>     <span class="o">=</span> <span class="n">RUNNING</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                 <span class="n">current_proc</span> <span class="o">=</span> <span class="n">p</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                 <span class="nf">swtch</span><span class="p">(</span><span class="o">&amp;</span><span class="n">idle</span><span class="p">.</span><span class="n">context</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">p</span><span class="o">-&gt;</span><span class="n">context</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="n">d208c5d</span><span class="p">.</span><span class="mf">.53576</span><span class="n">bf</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">proc</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">3</span><span class="p">,</span><span class="mi">7</span> <span class="o">+</span><span class="mi">3</span><span class="p">,</span><span class="mi">8</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;types.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="o">-</span><span class="err">#</span><span class="n">define</span> <span class="nf">NPROC</span> <span class="p">(</span><span class="mi">16</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">define</span> <span class="nf">NPROC</span>           <span class="p">(</span><span class="mi">16</span><span class="p">)</span>  <span class="c1">// 最大进程数
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">define</span> <span class="nf">MAX_SYSCALL_NUM</span> <span class="p">(</span><span class="mi">500</span><span class="p">)</span> <span class="c1">// 最大系统调用数
</span></span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="c1">// Saved registers for kernel context switches.
</span></span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">context</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">42</span><span class="p">,</span><span class="mi">14</span> <span class="o">+</span><span class="mi">43</span><span class="p">,</span><span class="mi">28</span> <span class="err">@@</span> <span class="k">struct</span> <span class="n">proc</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="n">uint64</span>            <span class="n">kstack</span><span class="p">;</span>    <span class="c1">// 进程内核栈虚拟地址 (内核页表)
</span></span></span><span class="line"><span class="cl">     <span class="k">struct</span> <span class="n">trapframe</span> <span class="o">*</span><span class="n">trapframe</span><span class="p">;</span> <span class="c1">// 进程中断帧
</span></span></span><span class="line"><span class="cl">     <span class="k">struct</span> <span class="n">context</span>    <span class="n">context</span><span class="p">;</span> <span class="c1">// 用于保存进程内核态的寄存器信息，进程切换时使用
</span></span></span><span class="line"><span class="cl"><span class="o">-</span>                               <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-	* LAB1: you may need to add some new fields here
</span></span></span><span class="line"><span class="cl"><span class="cm">+    /*
</span></span></span><span class="line"><span class="cl"><span class="cm">+	* LAB1: 添加一些新的成员用于新的 sys_task_info 系统调用
</span></span></span><span class="line"><span class="cl"><span class="cm"> 	*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint32</span> <span class="n">syscall_times</span><span class="p">[</span><span class="n">MAX_SYSCALL_NUM</span><span class="p">];</span> <span class="c1">// 系统调用次数统计 TODO: 后续改为指针
</span></span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint64</span> <span class="n">start_time</span><span class="p">;</span>                     <span class="c1">// 进程开始运行时间
</span></span></span><span class="line"><span class="cl"> <span class="p">};</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-* LAB1: you may need to define struct for TaskInfo here
</span></span></span><span class="line"><span class="cl"><span class="cm">+* LAB1: 定义 TaskInfo 结构体
</span></span></span><span class="line"><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">UnInit</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">Ready</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">Running</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">Exited</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="p">}</span> <span class="n">TaskStatus</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">TaskStatus</span> <span class="n">status</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint32</span>     <span class="n">syscall_times</span><span class="p">[</span><span class="n">MAX_SYSCALL_NUM</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="kt">int</span>        <span class="n">time</span><span class="p">;</span> <span class="c1">// 进程运行时间统计
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="p">}</span> <span class="n">TaskInfo</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="nf">curr_proc</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="kt">void</span>         <span class="nf">exit</span><span class="p">(</span><span class="kt">int</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="mi">1</span><span class="n">cc5aeb</span><span class="p">..</span><span class="n">f54ed86</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall</span><span class="p">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">4</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">4</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;syscall_ids.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;timer.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"> <span class="cp">#include</span> <span class="cpf">&#34;trap.h&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">include</span> <span class="s">&#34;proc.h&#34;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="n">uint64</span> <span class="nf">sys_write</span><span class="p">(</span><span class="kt">int</span> <span class="n">fd</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">str</span><span class="p">,</span> <span class="n">uint</span> <span class="n">len</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">31</span><span class="p">,</span><span class="mi">14</span> <span class="o">+</span><span class="mi">32</span><span class="p">,</span><span class="mi">46</span> <span class="err">@@</span> <span class="n">uint64</span> <span class="nf">sys_sched_yield</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="n">uint64</span> <span class="nf">sys_gettimeofday</span><span class="p">(</span><span class="n">TimeVal</span> <span class="o">*</span><span class="n">val</span><span class="p">,</span> <span class="kt">int</span> <span class="n">_tz</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="n">uint64</span> <span class="n">cycle</span> <span class="o">=</span> <span class="nf">get_cycle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">sec</span>     <span class="o">=</span> <span class="n">cycle</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">-</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">usec</span>    <span class="o">=</span> <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MICROSECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">tracef</span><span class="p">(</span><span class="s">&#34;sys_gettimeofday cycle = %d&#34;</span><span class="p">,</span> <span class="n">cycle</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">sec</span>  <span class="o">=</span> <span class="n">cycle</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">msec</span> <span class="o">=</span> <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MILLISECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">val</span><span class="o">-&gt;</span><span class="n">usec</span> <span class="o">=</span> <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MICROSECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="o">-</span><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-* LAB1: you may need to define sys_task_info here
</span></span></span><span class="line"><span class="cl"><span class="cm">-*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="cm">/** 
</span></span></span><span class="line"><span class="cl"><span class="cm">+ * LAB1：此处定义 sys_task_info 函数
</span></span></span><span class="line"><span class="cl"><span class="cm">+ * 查询当前正在执行的任务信息，任务信息包括任务控制块相关信息（任务状态）、任务使用的系统调用次数、任务总运行时长。 
</span></span></span><span class="line"><span class="cl"><span class="cm">+ */</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="kt">int</span> <span class="nf">sys_task_info</span><span class="p">(</span><span class="n">TaskInfo</span> <span class="o">*</span><span class="n">ti</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">struct</span> <span class="n">proc</span> <span class="o">*</span><span class="n">proc</span> <span class="o">=</span> <span class="nf">curr_proc</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="c1">// TODO: proc 检查为空
</span></span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">MAX_SYSCALL_NUM</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">proc</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint64</span> <span class="n">cycle</span> <span class="o">=</span> <span class="nf">get_cycle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint64</span> <span class="n">current_time</span> <span class="o">=</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="p">(</span><span class="n">cycle</span> <span class="o">%</span> <span class="n">CPU_FREQ</span><span class="p">)</span> <span class="o">*</span> <span class="n">MILLISECONDS_PER_SECOND</span> <span class="o">/</span> <span class="n">CPU_FREQ</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">infof</span><span class="p">(</span><span class="s">&#34;sys_task_info current_time = %d&#34;</span><span class="p">,</span> <span class="n">current_time</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">infof</span><span class="p">(</span><span class="s">&#34;proc-&gt;start_time = %d&#34;</span><span class="p">,</span> <span class="n">proc</span><span class="o">-&gt;</span><span class="n">start_time</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">infof</span><span class="p">(</span><span class="s">&#34;ti-&gt;time = %d&#34;</span><span class="p">,</span> <span class="n">current_time</span> <span class="o">-</span> <span class="n">proc</span><span class="o">-&gt;</span><span class="n">start_time</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">RUNNING</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">Running</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">RUNNABLE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">Ready</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">SLEEPING</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">Ready</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">ZOMBIE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">Exited</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">proc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">==</span> <span class="n">UNUSED</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ti</span><span class="o">-&gt;</span><span class="n">status</span> <span class="o">=</span> <span class="n">UnInit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">ti</span><span class="o">-&gt;</span><span class="n">time</span> <span class="o">=</span> <span class="n">current_time</span> <span class="o">-</span> <span class="n">proc</span><span class="o">-&gt;</span><span class="n">start_time</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">extern</span> <span class="kt">char</span> <span class="n">trap_page</span><span class="p">[];</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">51</span><span class="p">,</span><span class="mi">8</span> <span class="o">+</span><span class="mi">84</span><span class="p">,</span><span class="mi">9</span> <span class="err">@@</span> <span class="kt">void</span> <span class="nf">syscall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">     <span class="nf">tracef</span><span class="p">(</span><span class="s">&#34;syscall %d args = [%x, %x, %x, %x, %x, %x]&#34;</span><span class="p">,</span> <span class="n">id</span><span class="p">,</span> <span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="n">args</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">4</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">5</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">     <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-	* LAB1: you may need to update syscall counter for task info here
</span></span></span><span class="line"><span class="cl"><span class="cm">+	* LAB1: 更新系统调用次数
</span></span></span><span class="line"><span class="cl"><span class="cm"> 	*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="nf">curr_proc</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">syscall_times</span><span class="p">[</span><span class="n">id</span><span class="p">]</span><span class="o">++</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">switch</span> <span class="p">(</span><span class="n">id</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="k">case</span> <span class="nl">SYS_write</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">         <span class="n">ret</span> <span class="o">=</span> <span class="nf">sys_write</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">args</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">67</span><span class="p">,</span><span class="mi">8</span> <span class="o">+</span><span class="mi">101</span><span class="p">,</span><span class="mi">15</span> <span class="err">@@</span> <span class="kt">void</span> <span class="nf">syscall</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">         <span class="n">ret</span> <span class="o">=</span> <span class="nf">sys_gettimeofday</span><span class="p">((</span><span class="n">TimeVal</span> <span class="o">*</span><span class="p">)</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">args</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">         <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-	* LAB1: you may need to add SYS_taskinfo case here
</span></span></span><span class="line"><span class="cl"><span class="cm">+	* LAB1: 在此处添加 SYS_task_info 的系统调用处理情况
</span></span></span><span class="line"><span class="cl"><span class="cm"> 	*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">case</span> <span class="nl">SYS_task_info</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ret</span> <span class="o">=</span> <span class="nf">sys_task_info</span><span class="p">((</span><span class="n">TaskInfo</span> <span class="o">*</span><span class="p">)</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="k">case</span> <span class="nl">SYS_getpid</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="nf">infof</span><span class="p">(</span><span class="s">&#34;SYS_getpid %d&#34;</span><span class="p">,</span> <span class="n">SYS_getpid</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="n">ret</span> <span class="o">=</span> <span class="nf">curr_proc</span><span class="p">()</span><span class="o">-&gt;</span><span class="n">pid</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span>        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">     <span class="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">         <span class="n">ret</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="nf">errorf</span><span class="p">(</span><span class="s">&#34;unknown syscall %d&#34;</span><span class="p">,</span> <span class="n">id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="mo">05</span><span class="n">a6cb9</span><span class="p">.</span><span class="mf">.3</span><span class="n">c1a5a9</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">syscall_ids</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">277</span><span class="p">,</span><span class="mi">9</span> <span class="o">+</span><span class="mi">277</span><span class="p">,</span><span class="mi">8</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_io_pgetevents          292
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_rseq                   293
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_kexec_file_load        294
</span></span></span><span class="line"><span class="cl"><span class="o">-</span><span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">-* LAB1: you may need to define SYS_task_info here
</span></span></span><span class="line"><span class="cl"><span class="cm">-*/</span>
</span></span><span class="line"><span class="cl"><span class="o">+</span><span class="c1">// LAB1：添加 SYS_task_info 的系统调用号
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">define</span> <span class="n">SYS_task_info</span>          <span class="mi">410</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_pidfd_send_signal  424
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_io_uring_setup     425
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define SYS_io_uring_enter     426
</span></span></span><span class="line"><span class="cl"><span class="n">diff</span> <span class="o">--</span><span class="n">git</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="n">index</span> <span class="n">c6ebd14</span><span class="p">.</span><span class="mf">.63</span><span class="n">ab45c</span> <span class="mi">100644</span>
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">a</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="o">+++</span> <span class="n">b</span><span class="o">/</span><span class="n">os</span><span class="o">/</span><span class="n">timer</span><span class="p">.</span><span class="n">h</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">6</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#define TICKS_PER_SEC (100)
</span></span></span><span class="line"><span class="cl"> <span class="c1">// QEMU
</span></span></span><span class="line"><span class="cl"> <span class="cp">#define CPU_FREQ                (12500000)
</span></span></span><span class="line"><span class="cl"><span class="o">+</span><span class="err">#</span><span class="n">define</span> <span class="nf">MILLISECONDS_PER_SECOND</span> <span class="p">(</span><span class="mi">1000</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="cp">#define MICROSECONDS_PER_SECOND (1000000)
</span></span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="n">uint64</span> <span class="nf">get_cycle</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="err">@@</span> <span class="o">-</span><span class="mi">14</span><span class="p">,</span><span class="mi">6</span> <span class="o">+</span><span class="mi">15</span><span class="p">,</span><span class="mi">7</span> <span class="err">@@</span> <span class="kt">void</span>   <span class="nf">set_next_timer</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"> <span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="n">uint64</span> <span class="n">sec</span><span class="p">;</span>  <span class="c1">// 自 Unix 纪元起的秒数
</span></span></span><span class="line"><span class="cl"><span class="o">+</span>    <span class="n">uint64</span> <span class="n">msec</span><span class="p">;</span> <span class="c1">// 毫秒数
</span></span></span><span class="line"><span class="cl">     <span class="n">uint64</span> <span class="n">usec</span><span class="p">;</span> <span class="c1">// 微秒数
</span></span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="n">TimeVal</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl"><span class="o">--</span> 
</span></span><span class="line"><span class="cl"><span class="mf">2.34.1</span>
</span></span></code></pre></div><h1 id="问答作业">问答作业</h1>
<h2 id="问题一">问题一</h2>
<p>正确进入 U 态后，程序的特征还应有：使用 S 态特权指令，访问 S 态寄存器后会报错。请同学们可以自行测试这些内容（参考 前三个测例，描述程序出错行为，同时注意注明你使用的 sbi 及其版本。</p>
<p>测试前三个测试用例指的是<code>uCore-Tutorial-Code-2023S/user/src/</code> 目录下的三个<code>bad</code>测试用例，查看<code>user</code>项目的 Makefile 可以发现在编译时修改<code>CHAPTER</code>参数值为<code>2_bad</code>即可编译运行这些测试用例。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> RustSBI version 0.3.0-alpha.2, adapting to RISC-V SBI v1.0.0
</span></span><span class="line"><span class="cl">.______       __    __      _______.___________.  _______..______   __
</span></span><span class="line"><span class="cl"><span class="p">|</span>   _  <span class="se">\ </span>    <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>    /       <span class="p">|</span>           <span class="p">|</span> /       <span class="o">||</span>   _  <span class="se">\ </span><span class="p">|</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>  <span class="p">|</span>_<span class="o">)</span>  <span class="p">|</span>    <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>   <span class="p">|</span>   <span class="o">(</span>----<span class="sb">`</span>---<span class="p">|</span>  <span class="p">|</span>----<span class="sb">`</span><span class="p">|</span>   <span class="o">(</span>----<span class="sb">`</span><span class="p">|</span>  <span class="p">|</span>_<span class="o">)</span>  <span class="o">||</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>      /     <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>  <span class="p">|</span>    <span class="se">\ </span>  <span class="se">\ </span>      <span class="p">|</span>  <span class="p">|</span>      <span class="se">\ </span>  <span class="se">\ </span>   <span class="p">|</span>   _  &lt; <span class="p">|</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span>  <span class="p">|</span><span class="se">\ </span> <span class="se">\-</span>---.<span class="p">|</span>  <span class="sb">`</span>--<span class="err">&#39;</span>  <span class="p">|</span>.----<span class="o">)</span>   <span class="p">|</span>      <span class="p">|</span>  <span class="p">|</span>  .----<span class="o">)</span>   <span class="p">|</span>   <span class="p">|</span>  <span class="p">|</span>_<span class="o">)</span>  <span class="o">||</span>  <span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="p">|</span> _<span class="p">|</span> <span class="sb">`</span>._____<span class="p">|</span> <span class="se">\_</span>_____/ <span class="p">|</span>_______/       <span class="p">|</span>__<span class="p">|</span>  <span class="p">|</span>_______/    <span class="p">|</span>______/ <span class="p">|</span>__<span class="p">|</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Implementation     : RustSBI-QEMU Version 0.2.0-alpha.2
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Platform Name      : riscv-virtio,qemu
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Platform SMP       : <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Platform Memory    : 0x80000000..0x88000000
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Boot HART          : <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Device Tree Region : 0x87000000..0x87000ef2
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Firmware Address   : 0x80000000
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> Supervisor Address : 0x80200000
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> pmp01: 0x00000000..0x80000000 <span class="o">(</span>-wr<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> pmp02: 0x80000000..0x80200000 <span class="o">(</span>---<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> pmp03: 0x80200000..0x88000000 <span class="o">(</span>xwr<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>rustsbi<span class="o">]</span> pmp04: 0x88000000..0x00000000 <span class="o">(</span>-wr<span class="o">)</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>TRACE 0<span class="o">]</span>load app <span class="m">0</span> at 0x0000000080400000
</span></span><span class="line"><span class="cl"><span class="o">[</span>TRACE 0<span class="o">]</span>load app <span class="m">1</span> at 0x0000000080420000
</span></span><span class="line"><span class="cl"><span class="o">[</span>TRACE 0<span class="o">]</span>load app <span class="m">2</span> at 0x0000000080440000
</span></span><span class="line"><span class="cl"><span class="o">[</span>INFO 0<span class="o">]</span>start scheduler!
</span></span><span class="line"><span class="cl"><span class="o">[</span>ERROR 1<span class="o">]</span>unknown trap: 0x0000000000000007, <span class="nv">stval</span> <span class="o">=</span> 0x0000000000000000
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>INFO 1<span class="o">]</span>进程 <span class="m">1</span> 以代码 -1 退出
</span></span><span class="line"><span class="cl">IllegalInstruction in application, core dumped.
</span></span><span class="line"><span class="cl"><span class="o">[</span>INFO 2<span class="o">]</span>进程 <span class="m">2</span> 以代码 -3 退出
</span></span><span class="line"><span class="cl">IllegalInstruction in application, core dumped.
</span></span><span class="line"><span class="cl"><span class="o">[</span>INFO 3<span class="o">]</span>进程 <span class="m">3</span> 以代码 -3 退出
</span></span><span class="line"><span class="cl"><span class="o">[</span>PANIC 3<span class="o">]</span> os/loader.c:15: all apps over
</span></span></code></pre></div><p>第一个进程测试用例如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="kt">int</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>在您提供的代码中，将空指针分配给指针变量*p 后，试图对其进行解引用并将值 0 赋给该指针。由于用户模式下禁止直接访问物理内存，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped.</p>
<p>在 RISC-V 架构中，U 模式是最低的用户模式，用户程序无法直接访问物理内存或其他特权级别资源。这种限制是为了确保操作系统的安全性和稳定性。</p>
<p>第二个进程测试用例如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span><span class="s">&#34;sret&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>试图使用汇编语言执行 sret 指令，该指令用于从中断或异常处理程序返回。由于用户模式下禁止直接访问特权级别寄存器，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped。</p>
<p>第三个进程测试用例如下：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="n">uint64</span> <span class="n">x</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="k">asm</span> <span class="k">volatile</span><span class="p">(</span><span class="s">&#34;csrr %0, sstatus&#34;</span> <span class="o">:</span> <span class="s">&#34;=r&#34;</span><span class="p">(</span><span class="n">x</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>原因同上，试图使用汇编语言执行 csrr 指令，该指令用于从特权级别寄存器中读取值。由于用户模式下禁止直接访问特权级别寄存器，操作系统会检测到这个非法操作并触发异常。因此，该程序 IllegalInstruction in application, core dumped。</p>
<p>在操作系统代码中，触发异常后会进入<code>void usertrap()</code> 函数，该函数会根据 <code>scause</code> 寄存器的值判断异常类型，用例中的结果进入了<code>case IllegalInstruction</code>，其中 <code>IllegalInstruction = 2</code>。我们查阅手册 <code>riscv-privileged.pdf</code> ，可以查到 <code>IllegalInstruction</code> 的值为 2，与预期相符。</p>
<h2 id="问题二">问题二</h2>
<p>请结合用例理解 trampoline.S 中两个函数 <code>userret</code> 和 <code>uservec</code> 的作用，并回答如下几个问题：</p>
<h3 id="l79-刚进入-userret-时a0a1-分别代表了什么值">L79: 刚进入 <code>userret</code> 时，<code>a0</code>、<code>a1</code> 分别代表了什么值。</h3>
<p>在进入<code>userret</code>函数时，<code>a0</code>和<code>a1</code>分别代表以下值：</p>
<ul>
<li><code>a0</code>: TRAPFRAME 的地址，指向当前进程的陷阱帧（trapframe）结构体。</li>
<li><code>a1</code>: 用户页表的地址，即进程的页表（pagetable）。这个地址会被写入到<code>satp</code>寄存器中，用于切换到用户模式的页表。</li>
</ul>
<h3 id="l87-l88-sfence-指令有何作用为什么要执行该指令当前章节中删掉该指令会导致错误吗">L87-L88: <code>sfence</code> 指令有何作用？为什么要执行该指令，当前章节中，删掉该指令会导致错误吗？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-asm" data-lang="asm"><span class="line"><span class="cl"><span class="nf">csrw</span> <span class="no">satp</span><span class="p">,</span> <span class="no">a1</span>
</span></span><span class="line"><span class="cl"><span class="nf">sfence.vma</span> <span class="no">zero</span><span class="p">,</span> <span class="no">zero</span>
</span></span></code></pre></div><p><code>sfence</code>指令（Store Fence）的作用是确保之前的存储操作完成，并且对其他处理器上的核心可见。</p>
<p>执行<code>sfence</code>指令的主要目的是为了保证内存访问的顺序性和一致性。在多核处理器系统中，不同的核心可能会有自己的缓存，当一个核心修改了共享内存中的数据时，为了保证其他核心能够看到这个修改，需要使用<code>sfence</code>指令来刷新缓存并将修改写回共享内存。</p>
<p>在代码中，<code>sfence</code>指令被用于确保对用户页表的修改对其他处理器上的核心可见。因为目前我只使用了单核处理器，所以不会出现多核处理器的情况，因此<code>sfence</code>指令的作用是确保对用户页表的修改对当前核心可见。</p>
<p>因此，当前章节中，<strong>删掉该指令不会导致错误</strong>。</p>
<h3 id="l96-l125-为何注释中说要除去-a0哪一个地址代表-a0现在-a0-的值存在何处">L96-L125: 为何注释中说要除去 <code>a0</code>？哪一个地址代表 <code>a0</code>？现在 <code>a0</code> 的值存在何处？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># restore all but a0 from TRAPFRAME
</span></span><span class="line"><span class="cl">ld ra, 40(a0)
</span></span><span class="line"><span class="cl">ld sp, 48(a0)
</span></span><span class="line"><span class="cl">ld t5, 272(a0)
</span></span><span class="line"><span class="cl">ld t6, 280(a0)
</span></span></code></pre></div><p><code>a0</code> 是<strong>保存在 <code>sscratch</code> 寄存器中的</strong>，首先，该代码通过 <code>ld</code> 指令从 <code>TRAPFRAME</code> 中加载各个寄存器的值。然后，这些值被存储在相应的寄存器中，以便在恢复用户上下文时使用。</p>
<p>接下来，代码使用 <code>csrrw</code> 指令将 sscratch 寄存器的值与 <code>a0</code>（即 <code>TRAPFRAME</code>）进行交换。这样做是为了将用户的 <code>a0</code>（<code>TRAPFRAME</code>）保存在 <code>sscratch</code> 寄存器中，以便后续步骤可以正确地恢复用户上下文。</p>
<p>最后，通过 <code>sret</code> 指令返回到用户模式，并将控制权交给用户代码。在执行 <code>sret</code> 指令后，处理器将根据用户上下文中的 <code>sepc</code> 寄存器的值跳转到用户代码的指令地址。返回的同时，处理器还会自动恢复 <code>sstatus</code> 寄存器的值，以确保正确的特权级别和中断状态。</p>
<h3 id="userret中发生状态切换在哪一条指令为何执行之后会进入用户态"><code>userret</code>：中发生状态切换在哪一条指令？为何执行之后会进入用户态？</h3>
<p>在<code>userret</code>函数中，发生状态切换的指令是<code>sret</code>指令。</p>
<p><code>sret</code>指令用于从内核模式切换到用户模式，并将控制权交给用户代码。执行<code>sret</code>指令后，处理器会根据用户上下文中的<code>sepc</code>寄存器的值跳转到用户代码的指令地址。</p>
<p>执行<code>sret</code>指令之后进入用户态的原因是，该指令会自动恢复<code>sstatus</code>寄存器的值，以确保正确的特权级别和中断状态。当<code>sret</code>指令执行后，处理器将从内核态切换回用户态，程序将继续执行用户代码。这意味着<code>userret</code>函数成功完成了从内核切换到用户模式的过程。</p>
<h3 id="l29执行之后a0-和-sscratch-中各是什么值为什么">L29：执行之后，a0 和 sscratch 中各是什么值，为什么？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">csrrw a0, sscratch, a0     
</span></span></code></pre></div><p>在执行指令后，<code>a0</code>和<code>sscratch</code>中的值发生了互换。</p>
<p>假设原始<code>a0</code>寄存器中的值为 X，而<code>sscratch</code>寄存器中的值为 Y。执行<code>csrrw a0, sscratch, a0</code>指令后，<code>a0</code>寄存器中的值变为 Y，而<code>sscratch</code>寄存器中的值变为 X。</p>
<p>这是因为<code>csrrw</code>指令是一个特权指令，用于将某个 CSR（Control and Status Register）的值读取到目标寄存器，然后将目标寄存器的值写回到该 CSR 中。在这里，<code>csrrw a0, sscratch, a0</code>指令将<code>sscratch</code>寄存器的值读取到<code>a0</code>寄存器中，同时将<code>a0</code>寄存器中的值写回到<code>sscratch</code>寄存器中，从而实现了两者之间的数据交换。</p>
<h3 id="l32-l61-从-trapframe-第几项开始保存为什么是否从该项开始保存了所有的值如果不是为什么">L32-L61: 从 trapframe 第几项开始保存？为什么？是否从该项开始保存了所有的值，如果不是，为什么？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">sd ra, 40(a0)
</span></span><span class="line"><span class="cl">sd sp, 48(a0)
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">sd t5, 272(a0)
</span></span><span class="line"><span class="cl">sd t6, 280(a0)
</span></span></code></pre></div><h3 id="进入-s-态是哪一条指令发生的">进入 S 态是哪一条指令发生的？</h3>
<h3 id="l75-l76-ld-t0-16a0-执行之后t0中的值是什么解释该值的由来">L75-L76: <code>ld t0, 16(a0)</code> 执行之后，<code>t0</code>中的值是什么，解释该值的由来？</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ld t0, 16(a0)
</span></span><span class="line"><span class="cl">jr t0
</span></span></code></pre></div><p><code>ld t0, 16(a0)</code>就是从 <code>trapframe</code> 中恢复 <code>t0</code>寄存器值，<code>t0</code>保存了<code>kernel_trap</code>的入口地址。使用 <code>jr t0</code>，就跳转到了我们早先设定在 <code>trapframe-&gt;kernel_trap</code> 中的地址，也就是 <code>trap.c</code> 之中的 <code>usertrap</code> 函数。这个函数在 <code>main</code> 的初始化之中已经调用了。</p>
]]></content:encoded>
    </item>
    <item>
      <title>uCore 实验第 2 章 - 批处理系统</title>
      <link>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC2%E7%AB%A0-%E6%89%B9%E5%A4%84%E7%90%86%E7%B3%BB%E7%BB%9F/</link>
      <pubDate>Thu, 31 Aug 2023 23:16:38 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/ucore-%E5%AE%9E%E9%AA%8C%E7%AC%AC2%E7%AB%A0-%E6%89%B9%E5%A4%84%E7%90%86%E7%B3%BB%E7%BB%9F/</guid>
      <description>&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;flowchart&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subgraph&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;_entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subgraph&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;link_app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;S&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;_app_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_app_num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subgraph&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;subgraph&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loader&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;loader_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;loader_init&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;run_next_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;run_next_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;load_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;load_app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;_entry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;loader_init&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;run_next_app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;run_next_app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;loader_init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;_app_num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">flowchart</span> <span class="n">TB</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraph</span> <span class="n">entry</span><span class="o">.</span><span class="n">S</span>
</span></span><span class="line"><span class="cl">        <span class="n">_entry</span><span class="p">[</span><span class="n">_entry</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraph</span> <span class="n">link_app</span><span class="o">.</span><span class="n">S</span>
</span></span><span class="line"><span class="cl">        <span class="n">_app_num</span><span class="p">[</span><span class="n">_app_num</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraph</span> <span class="n">main</span><span class="o">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl">        <span class="n">main</span><span class="p">[</span><span class="n">main</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">end</span>
</span></span><span class="line"><span class="cl">    <span class="n">subgraph</span> <span class="n">loader</span><span class="o">.</span><span class="n">c</span>
</span></span><span class="line"><span class="cl">        <span class="n">loader_init</span><span class="p">[</span><span class="n">loader_init</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">run_next_app</span><span class="p">[</span><span class="n">run_next_app</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">load_app</span><span class="p">[</span><span class="n">load_app</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">_entry</span> <span class="o">--&gt;</span> <span class="n">main</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span> <span class="o">--&gt;</span> <span class="n">loader_init</span>
</span></span><span class="line"><span class="cl">    <span class="n">main</span> <span class="o">--&gt;</span> <span class="n">run_next_app</span>
</span></span><span class="line"><span class="cl">    <span class="n">run_next_app</span> <span class="o">--&gt;</span> <span class="n">load_app</span>
</span></span><span class="line"><span class="cl">    <span class="n">loader_init</span> <span class="o">--&gt;</span> <span class="n">_app_num</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>QEMU启动RISC-V架构OpenEuler并配置OSC环境</title>
      <link>https://lifeislife.cn/posts/qemu%E5%90%AF%E5%8A%A8risc-v%E6%9E%B6%E6%9E%84openeuler%E5%B9%B6%E9%85%8D%E7%BD%AEosc%E7%8E%AF%E5%A2%83/</link>
      <pubDate>Sun, 23 Jul 2023 19:28:29 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E5%90%AF%E5%8A%A8risc-v%E6%9E%B6%E6%9E%84openeuler%E5%B9%B6%E9%85%8D%E7%BD%AEosc%E7%8E%AF%E5%A2%83/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;基于Ubuntu 18.04，QEMU 8.0.2，OpenEuler 22.09&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;安装qemu&#34;&gt;安装QEMU&lt;/h1&gt;
&lt;h2 id=&#34;安装基础编译工具&#34;&gt;安装基础编译工具&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install build-essential autoconf automake autotools-dev pkg-config bc curl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 gawk git bison flex texinfo gperf libtool patchutils mingw-w64 libmpc-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 libmpfr-dev libgmp-dev libexpat-dev libfdt-dev zlib1g-dev libglib2.0-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 libpixman-1-dev libncurses5-dev libncursesw5-dev meson libvirglrenderer-dev libsdl2-dev  -y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo add-apt-repository ppa:deadsnakes/ppa
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install python3.8 python3-pip  -y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install -f
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip3 install meson
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;下载qemu&#34;&gt;下载QEMU&lt;/h2&gt;
&lt;p&gt;建立文件夹用于编译：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; mkdir -p qemu-build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;建立文件夹用于安装：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; mkdir -p /home/user/program/riscv64-qemu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可登录&lt;a href=&#34;https://www.qemu.org/download/&#34;&gt;官网&lt;/a&gt;将版本号换成最新版本即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; qemu-build &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; wget  &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://download.qemu.org/qemu-8.0.2.tar.xz&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;tar -xf qemu-8.0.2.tar.xz --strip-components&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;安装qemu-1&#34;&gt;安装QEMU&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; qemu-build &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./configure --target-list&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv32-softmmu,riscv32-linux-user,riscv64-linux-user,riscv64-softmmu &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               --enable-kvm --enable-sdl &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               --prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/home/user/program/riscv64-qemu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make install -j &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;nproc&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置环境变量&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;export QEMU_HOME=/home/user/program/riscv64-qemu&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;export PATH=$QEMU_HOME/bin:$PATH&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;下载-openeuler-risc-v-系统镜像&#34;&gt;下载 OpenEuler RISC-V 系统镜像&lt;/h1&gt;
&lt;p&gt;建立目录：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; mkdir -p /home/user/openeuler
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;根据自己的用户名修改user&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下载&lt;a href=&#34;https://repo.openeuler.org/openEuler-preview/RISC-V/openEuler-22.09-riscv64/QEMU/&#34;&gt;OpenEuler 22.09版本&lt;/a&gt;，下载目录下所有文件/home/user/openeuler。如需下载其他版本请进入其他目录选择下载即可。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;也可以根据自己的情况进入&lt;a href=&#34;https://www.openeuler.org/zh/mirror/list/&#34;&gt;镜像站列表&lt;/a&gt;选择下载速度更快的镜像站下载&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;最新的23.03版本需要在&lt;a href=&#34;https://mirror.iscas.ac.cn/openeuler-sig-riscv/openEuler-RISC-V/preview/openEuler-23.03-V1-riscv64/&#34;&gt;中科院镜像站&lt;/a&gt;下载&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;文件说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fw_payload_oe_qemuvirt.elf&lt;/code&gt;: 利用 openSBI 将 kernel-5.10 的 image 作为 payload 所制作的 QEMU 启动所需文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openEuler-22.09-qemu-xfce.qcow2.tar.zst&lt;/code&gt;: openEuler RISC-V QEMU GUI 镜像压缩包&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preview_start_vm_xfce.sh&lt;/code&gt;: GUI 虚拟机启动脚本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openeuler-22.09-qemu.qcow2.tar.zst&lt;/code&gt;: openEuler RISC-V QEMU headless 镜像压缩包&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preview_start_vm.sh&lt;/code&gt;: headless 虚拟机启动脚本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;解压：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; sudo apt-get install zstd
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; tar -I &lt;span class=&#34;s1&#34;&gt;&amp;#39;zstdmt&amp;#39;&lt;/span&gt; -xvf openEuler-22.09-riscv64-qemu.qcow2.tar.zst
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行启动脚本&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chmod +x preview_start_vm.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bash preview_start_vm.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;登录系统&#34;&gt;登录系统&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;用户名: &lt;code&gt;root&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;默认密码: &lt;code&gt;openEuler12#$&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openEuler 22.09
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Kernel 5.10.0 on an riscv64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4penEuler-riscv6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; login: openEuler 22.09
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Kernel 5.10.0 on an riscv64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;openEuler-riscv64 login: root
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Password: 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Welcome to 5.10.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;System information as of time:   Mon Jul  &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; 07:52:19 PM CST &lt;span class=&#34;m&#34;&gt;2023&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;System load:   0.17
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Processes:   &lt;span class=&#34;m&#34;&gt;117&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Memory used:   .6%
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Swap used:   0.0%
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Usage On:   6%
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Users online:   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;root@openEuler-riscv64 ~&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# ls&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;root@openEuler-riscv64 ~&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# pwd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;远程登录系统&#34;&gt;远程登录系统&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh -p &lt;span class=&#34;m&#34;&gt;12055&lt;/span&gt; root@localhost
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;配置系统&#34;&gt;配置系统&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;以下操作均在root用户下执行，如果切换了用户会有提示。因为系统初始状态没有普通用户，也没有sudo，所以需要使用root完成一些基础配置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;修改root密码&#34;&gt;修改root密码&lt;/h2&gt;
&lt;p&gt;原密码太复杂，修改简单密码&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;passwd root
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输入两次密码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;添加普通用户&#34;&gt;添加普通用户&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 添加用户 user&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;useradd -s /bin/bash -d /home/user -m user
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;passwd user
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输入两次密码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 添加管理员权限&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;usermod -aG wheel user
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;修改时间&#34;&gt;修改时间&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;NTP=ntp.aliyun.com&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; /etc/systemd/timesyncd.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl restart systemd-timesyncd.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看&lt;code&gt;timesyncd&lt;/code&gt;运行状态：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl status systemd-timesyncd.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;date&lt;/code&gt;命令可查看当前系统时间。验证是否配置成功。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;时间务必正确设置&lt;/strong&gt;，错误的时间会影响诸如https的TLS认证等过程。&lt;/p&gt;
&lt;h2 id=&#34;配置dns&#34;&gt;配置DNS&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vim /etc/resolv.conf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nameserver 119.29.29.29
&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;配置文件为 /etc/yum.repos.d/openEuler.repo 下&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv /etc/yum.repos.d/openEuler.repo  /etc/yum.repos.d/openEuler.repo.bk &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo bash -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;cat &amp;lt;&amp;lt; EOF &amp;gt; /etc/yum.repos.d/openEuler.repo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;# just for test
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;[mainline]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;name=mainline
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;baseurl=https://mirror.iscas.ac.cn/openeuler-sig-riscv/openEuler-RISC-V/preview/openEuler-22.09-V1-riscv64/repo/22.09/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;enabled=1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;gpgcheck=0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;# just for test
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;[epol]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;name=epol
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;baseurl=https://mirror.iscas.ac.cn/openeuler-sig-riscv/openEuler-RISC-V/preview/openEuler-22.09-V1-riscv64/repo/22.09/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;enabled=1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;gpgcheck=0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;[extra]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;name=extra
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;baseurl=https://mirror.iscas.ac.cn/openeuler-sig-riscv/openEuler-RISC-V/preview/openEuler-22.09-V1-riscv64/repo/extra/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;enabled=1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;gpgcheck=0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;EOF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;需要注意的是，因为OpenEuler还在快速发展中，镜像地址可能会发生变化，所以需确认地址是否能够正常访问，如无法访问会导致404错误&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;[repoid]中的repoid为软件仓库（repository）的ID号，所有.repo配置文件中的各repoid不能重复，必须唯一。示例中repoid设置为base。
name为软件仓库描述的字符串。
baseurl为软件仓库的地址。
enabled为是否启用该软件源仓库，可选值为1和0。默认值为1，表示启用该软件源仓库。
gpgcheck可设置为1或0，1表示进行gpg（GNU Private Guard）校验，0表示不进行gpg校验，gpgcheck可以确定rpm包的来源是有效和安全的。
gpgkey为验证签名用的公钥。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;磁盘扩容&#34;&gt;磁盘扩容&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;在宿主机上安装 &lt;code&gt;qemu-img&lt;/code&gt; 工具:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apt install qemu-utils
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;在 openEuler RISC-V 虚拟机上安装 &lt;code&gt;growpart&lt;/code&gt; 工具:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;dnf install cloud-utils-growpart
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;关闭QEMU虚拟机&lt;/li&gt;
&lt;li&gt;把 qcow2 文件的容量加200GB：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ qemu-img resize *.qcow2 +200G
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Image resized.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ qemu-img info *.qcow2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;image: openEuler-preview.riscv64.qcow2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;file format: qcow2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;virtual size: &lt;span class=&#34;m&#34;&gt;220&lt;/span&gt; GiB 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;disk size: 9.58 GiB
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cluster_size: &lt;span class=&#34;m&#34;&gt;65536&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Format specific information:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    compat: 1.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    compression type: zlib
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    lazy refcounts: &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    refcount bits: &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    corrupt: &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    extended l2: &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;5&#34;&gt;
&lt;li&gt;QEMU 启动 openEuler RISC-V。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;启动以后，我们先看看分区情况：可以看到根目录对应的分区只使用了 10G。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;root@openEuler-RISCV-rare ~&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# lsblk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vda    254:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  220G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└─vda1 254:1    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;   10G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; part /
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;扩展分区 &lt;code&gt;vda1&lt;/code&gt;，执行&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;growpart /dev/vda1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行 &lt;code&gt;lsblk&lt;/code&gt; 可以看到 / 所在的 &lt;code&gt;vda1&lt;/code&gt; 分区已经扩展到了预期大小&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;root@openEuler-RISCV-rare ~&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# growpart /dev/vda 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;CHANGED: &lt;span class=&#34;nv&#34;&gt;partition&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;2048&lt;/span&gt; old: &lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;20969472&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;20971520&lt;/span&gt; new: &lt;span class=&#34;nv&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;419428319&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;419430367&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;root@openEuler-RISCV-rare ~&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# lsblk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vda    254:0    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  220G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; disk
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└─vda1 254:1    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;  220G  &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; part /
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;扩展文件系统：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;resize2fs /dev/vda1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;bug&#34;&gt;BUG&lt;/h1&gt;
&lt;h2 id=&#34;network-backend-user-is-not-compiled-into-this-binary&#34;&gt;network backend ‘user‘ is not compiled into this binary&lt;/h2&gt;
&lt;p&gt;git clone &lt;a href=&#34;https://gitlab.freedesktop.org/slirp/libslirp.git&#34;&gt;https://gitlab.freedesktop.org/slirp/libslirp.git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://security.ubuntu.com/ubuntu/pool/main/libs/libslirp/libslirp-dev_4.1.0-2ubuntu2.2_amd64.deb&#34;&gt;http://security.ubuntu.com/ubuntu/pool/main/libs/libslirp/libslirp-dev_4.1.0-2ubuntu2.2_amd64.deb&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install libslirp-dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重新编译QEMU：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; qemu-build &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -rf build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; qemu-build &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./configure --target-list&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;riscv32-softmmu,riscv32-linux-user,riscv64-linux-user,riscv64-softmmu &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               --enable-kvm --enable-sdl --enable-slirp&lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               --prefix&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/home/user/program/riscv64-qemu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Bash&#34; data-lang=&#34;Bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make install -j &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;nproc&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;参考文档&#34;&gt;参考文档&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/openeuler-mirror/RISC-V/blob/master/doc/tutorials/vm-qemu-oErv.md&#34;&gt;RISC-V/doc/tutorials/vm-qemu-oErv.md at master · openeuler-mirror/RISC-V · GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.openeuler.org/whitepaper/openEuler-whitepaper-2209.pdf&#34;&gt;openEuler 22.09技术白皮书&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<blockquote>
<p>基于Ubuntu 18.04，QEMU 8.0.2，OpenEuler 22.09</p>
</blockquote>
<h1 id="安装qemu">安装QEMU</h1>
<h2 id="安装基础编译工具">安装基础编译工具</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo apt install build-essential autoconf automake autotools-dev pkg-config bc curl <span class="se">\
</span></span></span><span class="line"><span class="cl">                 gawk git bison flex texinfo gperf libtool patchutils mingw-w64 libmpc-dev <span class="se">\
</span></span></span><span class="line"><span class="cl">                 libmpfr-dev libgmp-dev libexpat-dev libfdt-dev zlib1g-dev libglib2.0-dev <span class="se">\
</span></span></span><span class="line"><span class="cl">                 libpixman-1-dev libncurses5-dev libncursesw5-dev meson libvirglrenderer-dev libsdl2-dev  -y
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo add-apt-repository ppa:deadsnakes/ppa
</span></span><span class="line"><span class="cl">sudo apt install python3.8 python3-pip  -y
</span></span><span class="line"><span class="cl">sudo apt install -f
</span></span><span class="line"><span class="cl">pip3 install meson
</span></span></code></pre></div><h2 id="下载qemu">下载QEMU</h2>
<p>建立文件夹用于编译：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="o">&amp;&amp;</span> mkdir -p qemu-build
</span></span></code></pre></div><p>建立文件夹用于安装：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="o">&amp;&amp;</span> mkdir -p /home/user/program/riscv64-qemu
</span></span></code></pre></div><p>可登录<a href="https://www.qemu.org/download/">官网</a>将版本号换成最新版本即可：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> qemu-build <span class="o">&amp;&amp;</span> wget  <span class="s2">&#34;https://download.qemu.org/qemu-8.0.2.tar.xz&#34;</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">tar -xf qemu-8.0.2.tar.xz --strip-components<span class="o">=</span><span class="m">1</span> 
</span></span></code></pre></div><h2 id="安装qemu-1">安装QEMU</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> qemu-build <span class="o">&amp;&amp;</span> ./configure --target-list<span class="o">=</span>riscv32-softmmu,riscv32-linux-user,riscv64-linux-user,riscv64-softmmu <span class="se">\
</span></span></span><span class="line"><span class="cl">               --enable-kvm --enable-sdl <span class="se">\
</span></span></span><span class="line"><span class="cl">               --prefix<span class="o">=</span>/home/user/program/riscv64-qemu
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">make install -j <span class="k">$(</span>nproc<span class="k">)</span>
</span></span></code></pre></div><p>配置环境变量</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;export QEMU_HOME=/home/user/program/riscv64-qemu&#39;</span> &gt;&gt; ~/.bashrc <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s1">&#39;export PATH=$QEMU_HOME/bin:$PATH&#39;</span> &gt;&gt; ~/.bashrc
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">source</span> ~/.bashrc
</span></span></code></pre></div><h1 id="下载-openeuler-risc-v-系统镜像">下载 OpenEuler RISC-V 系统镜像</h1>
<p>建立目录：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> <span class="o">&amp;&amp;</span> mkdir -p /home/user/openeuler
</span></span></code></pre></div><blockquote>
<p>根据自己的用户名修改user</p>
</blockquote>
<p>下载<a href="https://repo.openeuler.org/openEuler-preview/RISC-V/openEuler-22.09-riscv64/QEMU/">OpenEuler 22.09版本</a>，下载目录下所有文件/home/user/openeuler。如需下载其他版本请进入其他目录选择下载即可。</p>
<blockquote>
<p>也可以根据自己的情况进入<a href="https://www.openeuler.org/zh/mirror/list/">镜像站列表</a>选择下载速度更快的镜像站下载</p>
</blockquote>
<blockquote>
<p>最新的23.03版本需要在<a href="https://mirror.iscas.ac.cn/openeuler-sig-riscv/openEuler-RISC-V/preview/openEuler-23.03-V1-riscv64/">中科院镜像站</a>下载</p>
</blockquote>
<p>文件说明：</p>
<ul>
<li><code>fw_payload_oe_qemuvirt.elf</code>: 利用 openSBI 将 kernel-5.10 的 image 作为 payload 所制作的 QEMU 启动所需文件</li>
<li><code>openEuler-22.09-qemu-xfce.qcow2.tar.zst</code>: openEuler RISC-V QEMU GUI 镜像压缩包</li>
<li><code>preview_start_vm_xfce.sh</code>: GUI 虚拟机启动脚本</li>
<li><code>openeuler-22.09-qemu.qcow2.tar.zst</code>: openEuler RISC-V QEMU headless 镜像压缩包</li>
<li><code>preview_start_vm.sh</code>: headless 虚拟机启动脚本</li>
</ul>
<p>解压：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"> sudo apt-get install zstd
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"> tar -I <span class="s1">&#39;zstdmt&#39;</span> -xvf openEuler-22.09-riscv64-qemu.qcow2.tar.zst
</span></span></code></pre></div><p>执行启动脚本</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">chmod +x preview_start_vm.sh
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">bash preview_start_vm.sh
</span></span></code></pre></div><h1 id="登录系统">登录系统</h1>
<ul>
<li>用户名: <code>root</code></li>
<li>默认密码: <code>openEuler12#$</code></li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">openEuler 22.09
</span></span><span class="line"><span class="cl">Kernel 5.10.0 on an riscv64
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4penEuler-riscv6
</span></span><span class="line"><span class="cl"> login: openEuler 22.09
</span></span><span class="line"><span class="cl">Kernel 5.10.0 on an riscv64
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">openEuler-riscv64 login: root
</span></span><span class="line"><span class="cl">Password: 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Welcome to 5.10.0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">System information as of time:   Mon Jul  <span class="m">3</span> 07:52:19 PM CST <span class="m">2023</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">System load:   0.17
</span></span><span class="line"><span class="cl">Processes:   <span class="m">117</span>
</span></span><span class="line"><span class="cl">Memory used:   .6%
</span></span><span class="line"><span class="cl">Swap used:   0.0%
</span></span><span class="line"><span class="cl">Usage On:   6%
</span></span><span class="line"><span class="cl">Users online:   <span class="m">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">[</span>root@openEuler-riscv64 ~<span class="o">]</span><span class="c1"># ls</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>root@openEuler-riscv64 ~<span class="o">]</span><span class="c1"># pwd</span>
</span></span></code></pre></div><h3 id="远程登录系统">远程登录系统</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">ssh -p <span class="m">12055</span> root@localhost
</span></span></code></pre></div><h1 id="配置系统">配置系统</h1>
<blockquote>
<p>以下操作均在root用户下执行，如果切换了用户会有提示。因为系统初始状态没有普通用户，也没有sudo，所以需要使用root完成一些基础配置。</p>
</blockquote>
<h2 id="修改root密码">修改root密码</h2>
<p>原密码太复杂，修改简单密码</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">passwd root
</span></span><span class="line"><span class="cl"><span class="c1"># 输入两次密码</span>
</span></span></code></pre></div><h2 id="添加普通用户">添加普通用户</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="c1"># 添加用户 user</span>
</span></span><span class="line"><span class="cl">useradd -s /bin/bash -d /home/user -m user
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">passwd user
</span></span><span class="line"><span class="cl"><span class="c1"># 输入两次密码</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="c1"># 添加管理员权限</span>
</span></span><span class="line"><span class="cl">usermod -aG wheel user
</span></span></code></pre></div><h2 id="修改时间">修改时间</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;NTP=ntp.aliyun.com&#34;</span> &gt;&gt; /etc/systemd/timesyncd.conf
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">systemctl restart systemd-timesyncd.service
</span></span></code></pre></div><p>查看<code>timesyncd</code>运行状态：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">systemctl status systemd-timesyncd.service
</span></span></code></pre></div><p><code>date</code>命令可查看当前系统时间。验证是否配置成功。</p>
<p><strong>时间务必正确设置</strong>，错误的时间会影响诸如https的TLS认证等过程。</p>
<h2 id="配置dns">配置DNS</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">vim /etc/resolv.conf
</span></span><span class="line"><span class="cl">nameserver 119.29.29.29
</span></span></code></pre></div><h2 id="配置软件包源">配置软件包源</h2>
<p>配置文件为 /etc/yum.repos.d/openEuler.repo 下</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">mv /etc/yum.repos.d/openEuler.repo  /etc/yum.repos.d/openEuler.repo.bk <span class="o">&amp;&amp;</span> sudo bash -c <span class="s2">&#34;cat &lt;&lt; EOF &gt; /etc/yum.repos.d/openEuler.repo
</span></span></span><span class="line"><span class="cl"><span class="s2"># just for test
</span></span></span><span class="line"><span class="cl"><span class="s2">[mainline]
</span></span></span><span class="line"><span class="cl"><span class="s2">name=mainline
</span></span></span><span class="line"><span class="cl"><span class="s2">baseurl=https://mirror.iscas.ac.cn/openeuler-sig-riscv/openEuler-RISC-V/preview/openEuler-22.09-V1-riscv64/repo/22.09/
</span></span></span><span class="line"><span class="cl"><span class="s2">enabled=1
</span></span></span><span class="line"><span class="cl"><span class="s2">gpgcheck=0
</span></span></span><span class="line"><span class="cl"><span class="s2"># just for test
</span></span></span><span class="line"><span class="cl"><span class="s2">[epol]
</span></span></span><span class="line"><span class="cl"><span class="s2">name=epol
</span></span></span><span class="line"><span class="cl"><span class="s2">baseurl=https://mirror.iscas.ac.cn/openeuler-sig-riscv/openEuler-RISC-V/preview/openEuler-22.09-V1-riscv64/repo/22.09/
</span></span></span><span class="line"><span class="cl"><span class="s2">enabled=1
</span></span></span><span class="line"><span class="cl"><span class="s2">gpgcheck=0
</span></span></span><span class="line"><span class="cl"><span class="s2">[extra]
</span></span></span><span class="line"><span class="cl"><span class="s2">name=extra
</span></span></span><span class="line"><span class="cl"><span class="s2">baseurl=https://mirror.iscas.ac.cn/openeuler-sig-riscv/openEuler-RISC-V/preview/openEuler-22.09-V1-riscv64/repo/extra/
</span></span></span><span class="line"><span class="cl"><span class="s2">enabled=1
</span></span></span><span class="line"><span class="cl"><span class="s2">gpgcheck=0
</span></span></span><span class="line"><span class="cl"><span class="s2">EOF&#34;</span>
</span></span></code></pre></div><blockquote>
<p>需要注意的是，因为OpenEuler还在快速发展中，镜像地址可能会发生变化，所以需确认地址是否能够正常访问，如无法访问会导致404错误</p>
</blockquote>
<blockquote>
<p>[repoid]中的repoid为软件仓库（repository）的ID号，所有.repo配置文件中的各repoid不能重复，必须唯一。示例中repoid设置为base。
name为软件仓库描述的字符串。
baseurl为软件仓库的地址。
enabled为是否启用该软件源仓库，可选值为1和0。默认值为1，表示启用该软件源仓库。
gpgcheck可设置为1或0，1表示进行gpg（GNU Private Guard）校验，0表示不进行gpg校验，gpgcheck可以确定rpm包的来源是有效和安全的。
gpgkey为验证签名用的公钥。</p>
</blockquote>
<h2 id="磁盘扩容">磁盘扩容</h2>
<ol>
<li>在宿主机上安装 <code>qemu-img</code> 工具:</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">apt install qemu-utils
</span></span></code></pre></div><ol start="2">
<li>在 openEuler RISC-V 虚拟机上安装 <code>growpart</code> 工具:</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">dnf install cloud-utils-growpart
</span></span></code></pre></div><ol start="3">
<li>关闭QEMU虚拟机</li>
<li>把 qcow2 文件的容量加200GB：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">$ qemu-img resize *.qcow2 +200G
</span></span><span class="line"><span class="cl">Image resized.
</span></span><span class="line"><span class="cl">$ qemu-img info *.qcow2
</span></span><span class="line"><span class="cl">image: openEuler-preview.riscv64.qcow2
</span></span><span class="line"><span class="cl">file format: qcow2
</span></span><span class="line"><span class="cl">virtual size: <span class="m">220</span> GiB 
</span></span><span class="line"><span class="cl">disk size: 9.58 GiB
</span></span><span class="line"><span class="cl">cluster_size: <span class="m">65536</span>
</span></span><span class="line"><span class="cl">Format specific information:
</span></span><span class="line"><span class="cl">    compat: 1.1
</span></span><span class="line"><span class="cl">    compression type: zlib
</span></span><span class="line"><span class="cl">    lazy refcounts: <span class="nb">false</span>
</span></span><span class="line"><span class="cl">    refcount bits: <span class="m">16</span>
</span></span><span class="line"><span class="cl">    corrupt: <span class="nb">false</span>
</span></span><span class="line"><span class="cl">    extended l2: <span class="nb">false</span>
</span></span></code></pre></div><ol start="5">
<li>QEMU 启动 openEuler RISC-V。</li>
</ol>
<p>启动以后，我们先看看分区情况：可以看到根目录对应的分区只使用了 10G。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="o">[</span>root@openEuler-RISCV-rare ~<span class="o">]</span><span class="c1"># lsblk</span>
</span></span><span class="line"><span class="cl">NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
</span></span><span class="line"><span class="cl">vda    254:0    <span class="m">0</span>  220G  <span class="m">0</span> disk
</span></span><span class="line"><span class="cl">└─vda1 254:1    <span class="m">0</span>   10G  <span class="m">0</span> part /
</span></span></code></pre></div><ol>
<li>扩展分区 <code>vda1</code>，执行</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">growpart /dev/vda1
</span></span></code></pre></div><p>执行 <code>lsblk</code> 可以看到 / 所在的 <code>vda1</code> 分区已经扩展到了预期大小</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="o">[</span>root@openEuler-RISCV-rare ~<span class="o">]</span><span class="c1"># growpart /dev/vda 1</span>
</span></span><span class="line"><span class="cl">CHANGED: <span class="nv">partition</span><span class="o">=</span><span class="m">1</span> <span class="nv">start</span><span class="o">=</span><span class="m">2048</span> old: <span class="nv">size</span><span class="o">=</span><span class="m">20969472</span> <span class="nv">end</span><span class="o">=</span><span class="m">20971520</span> new: <span class="nv">size</span><span class="o">=</span><span class="m">419428319</span> <span class="nv">end</span><span class="o">=</span><span class="m">419430367</span>
</span></span><span class="line"><span class="cl"><span class="o">[</span>root@openEuler-RISCV-rare ~<span class="o">]</span><span class="c1"># lsblk</span>
</span></span><span class="line"><span class="cl">NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
</span></span><span class="line"><span class="cl">vda    254:0    <span class="m">0</span>  220G  <span class="m">0</span> disk
</span></span><span class="line"><span class="cl">└─vda1 254:1    <span class="m">0</span>  220G  <span class="m">0</span> part /
</span></span></code></pre></div><ol>
<li>扩展文件系统：</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">resize2fs /dev/vda1
</span></span></code></pre></div><h1 id="bug">BUG</h1>
<h2 id="network-backend-user-is-not-compiled-into-this-binary">network backend ‘user‘ is not compiled into this binary</h2>
<p>git clone <a href="https://gitlab.freedesktop.org/slirp/libslirp.git">https://gitlab.freedesktop.org/slirp/libslirp.git</a></p>
<p><a href="http://security.ubuntu.com/ubuntu/pool/main/libs/libslirp/libslirp-dev_4.1.0-2ubuntu2.2_amd64.deb">http://security.ubuntu.com/ubuntu/pool/main/libs/libslirp/libslirp-dev_4.1.0-2ubuntu2.2_amd64.deb</a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">sudo apt-get install libslirp-dev
</span></span></code></pre></div><p>重新编译QEMU：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> qemu-build <span class="o">&amp;&amp;</span> rm -rf build
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nb">cd</span> qemu-build <span class="o">&amp;&amp;</span> ./configure --target-list<span class="o">=</span>riscv32-softmmu,riscv32-linux-user,riscv64-linux-user,riscv64-softmmu <span class="se">\
</span></span></span><span class="line"><span class="cl">               --enable-kvm --enable-sdl --enable-slirp<span class="se">\
</span></span></span><span class="line"><span class="cl">               --prefix<span class="o">=</span>/home/user/program/riscv64-qemu
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">make install -j <span class="k">$(</span>nproc<span class="k">)</span>
</span></span></code></pre></div><h1 id="参考文档">参考文档</h1>
<p><a href="https://github.com/openeuler-mirror/RISC-V/blob/master/doc/tutorials/vm-qemu-oErv.md">RISC-V/doc/tutorials/vm-qemu-oErv.md at master · openeuler-mirror/RISC-V · GitHub</a></p>
<p><a href="https://www.openeuler.org/whitepaper/openEuler-whitepaper-2209.pdf">openEuler 22.09技术白皮书</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>ZH-The RISC-V Instruction Set Manual Volume 2-特权级架构</title>
      <link>https://lifeislife.cn/posts/zh-the-risc-v-instruction-set-manual-volume-2-%E7%89%B9%E6%9D%83%E7%BA%A7%E6%9E%B6%E6%9E%84/</link>
      <pubDate>Thu, 22 Sep 2022 09:37:54 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/zh-the-risc-v-instruction-set-manual-volume-2-%E7%89%B9%E6%9D%83%E7%BA%A7%E6%9E%B6%E6%9E%84/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Document Version 20211203&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&#34;control-and-status-registers-csrs&#34;&gt;Control and Status Registers (CSRs)&lt;/h1&gt;
&lt;h1 id=&#34;machine-level-isa-version-112&#34;&gt;Machine-Level ISA, Version 1.12&lt;/h1&gt;
&lt;p&gt;本章介绍了机器模式（M-mode）中可用的机器级操作，这是 RISC-V 系统中最高权限的模式。M 模式用于对硬件平台的低级访问，是复位时进入的第一个模式。M 模式也可以用来实现那些在硬件中直接实现过于困难或成本高昂的功能。RISC-V 的机器级 ISA 包含一个共同的核心，根据支持的其他权限级别和硬件实现的其他细节来扩展。&lt;/p&gt;
&lt;h2 id=&#34;machine-level-csrs&#34;&gt;Machine-Level CSRs&lt;/h2&gt;
&lt;p&gt;除了本节中描述的机器级 CSRs 外，M-mode 代码还可以访问较低特权级别的所有 CSRs。&lt;/p&gt;
&lt;h3 id=&#34;machine-isa-register-misa&#34;&gt;Machine ISA Register &lt;code&gt;misa&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;misa CSR 是 WARL 读写寄存器，报告硬件 (hart) 支持的 ISA。该寄存器在任何实现中都必须是可读的，但是可以返回零值以指示未实现 misa 寄存器，这就需要通过一个单独的非标准机制确定 CPU 功能。&lt;/p&gt;
&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;MXL（机器 XLEN）字段编码本机基本整数 ISA 宽度，如表 3.1 所示。MXL 字段在支持多个基本 ISA 宽度的实现中可能是可写的。M-mode 下的有效 XLEN, MXLEN，由 MXL 的设置给出，如果 misa 为零，则有一个固定的值。重置时，MXL 字段始终设置为最广泛支持的 ISA 变种。&lt;/p&gt;
&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;misa CSR 为 MXLEN 位宽。如果从 misa 读取的值不为零，该值的 MXL 字段总是表示当前的 MXLEN。如果对 misa 的写操作导致 MXLEN 发生更改，则 MXL 的位置将以新的宽度移动到 misa 的最高有效两位。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;可以使用返回的 misa 值的符号上的分支，以及可能在符号上左移一个分支和第二个分支，来快速确定基本宽度。这些检查可以用汇编代码编写，而无需知道机器的寄存器宽度（XLEN）。基本宽度由 XLEN = 2^(MXL + 4) 给出。如果 misa 为零，则可以通过将立即数 4 放置在一个寄存器中，然后一次将寄存器左移 31 位来找到基本宽度。如果在一次移位后为零，则该机器为 RV32。如果两次移位后为零，则机器为 RV64，否则为 RV128。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Extensions 字段编码了目前存有的标准扩展，其每个 bit 都对应了字母表中的一个字母（bit 0 编码扩展“A”是否存在，bit 1 编码扩展“B”是否存在&amp;hellip; 直至 bit 25 编码“Z”）。如果基础 ISA 是 RV32I、RV64I 或 RV128I，则置位“I”bit，否则如果基础 ISA 是 RV32E，则置位“E”bit。&lt;/p&gt;
&lt;p&gt;Extensions 字段是一个能包含可写位的 WARL 字段（如果实现允许修改所支持的 ISA）。&lt;/p&gt;
&lt;p&gt;复位（reset）时，Extensions 应包含所支持扩展的最大集，如果 E 和 I 都可用，则优先选择 I。&lt;/p&gt;
&lt;p&gt;在通过清除 misa 中相应 bit 来禁止一个标准扩展时，由该扩展所定义或修改的指令和 CSR 将恢复为该扩展未实现时的定义，或者保留行为（revert to their defined or reserved behaviors as if the extension is not implemented）。&lt;/p&gt;
&lt;p&gt;RV128 base ISA 的设计尚未完工，尽管预计本 specification 中大部分的剩余部分都将适用于 RV128，但本版本的文档仅关注 RV32 和 RV64。&lt;/p&gt;
&lt;p&gt;如果支持用户模式（user mode），则将“U”bit 置位；如果支持主管模式（supervisor mode），则将“S”bit 置位。&lt;/p&gt;
&lt;p&gt;如果存在任何非标准扩展（non-standard extensions），则将“X”bit 置位。&lt;/p&gt;
&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;“E”位是只读的。除非将 misa 硬连线为零，否则“E”位始终读取为“I”位的补码（补集？）。同时支持 RV32E 和 RV32I 的实现可以通过清除“I”位来选择 RV32E。&lt;/p&gt;
&lt;p&gt;如果 ISA 功能 x 依赖 ISA 功能 y，则尝试启用功能 x 但禁用功能 y 会导致两个功能都被禁用。例如，设置“F” = 0 和“D” = 1 会导致同时清除“F”和“D”。&lt;/p&gt;
&lt;p&gt;具体实现可能会在 2 或多个 misa 字段的集体设置上施加额外约束，此时将它们的集体看作是一个 WARL 字段。试图向其中写入一个不支持的组合会导致这些 bits 被置为某个支持的组合。&lt;/p&gt;
&lt;p&gt;写 misa 可能会增加 IALIGN，例如，通过禁用 C 扩展。如果要写入 misa 的指令增加了 IALIGN，而后一条指令的地址未按 IALIGN 位对齐，则将抑制对 misa 的写入，从而使 misa 保持不变。&lt;/p&gt;
&lt;p&gt;在软件启用一个之前被禁用的扩展时，除该扩展另有规定（specified），否则所有单独与该扩展有关的状态都将是未指定的（unspecified）。&lt;/p&gt;
&lt;h3 id=&#34;machine-vendor-id-register-mvendorid&#34;&gt;Machine Vendor ID Register &lt;code&gt;mvendorid&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;mvendorid&lt;/code&gt; CSR 是一个 32 位只读寄存器，提供内核供应商的 JEDEC 制造商 ID。此寄存器在任何实现中都必须是可读的，但可以返回 0，表示该字段未实现或这是非商业实现。&lt;/p&gt;
&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;JEDEC 制造商 ID 通常编码为单字节连续的 &lt;code&gt;0x7f&lt;/code&gt; 代码的序列，以不等于 &lt;code&gt;0x7f&lt;/code&gt; 的单字节 ID 终止，并且在每个字节的最高有效位中带有奇校验位。&lt;code&gt;mvendorid&lt;/code&gt; 在 Bank 字段中编码单字节的连续代码，并在 &lt;code&gt;Offset&lt;/code&gt; 字段中编码最后一个字节，丢弃奇偶校验位。例如，JEDEC 制造商 ID &lt;code&gt;0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x8a&lt;/code&gt;（十二个连续代码，后跟 0x8a）将在 mvendorid 字段中编码为 &lt;code&gt;0x60a&lt;/code&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;译者注：JEDEC 固态技术协会（JEDEC Solid State Technology Association）是固态及半导体工业界的一个标准化组织，它由约 300 家公司成员组成，约 3300 名技术人员通过 50 个不同的委员会运作，制定固态电子方面的工业标准。JEDEC 曾经是电子工业联盟（EIA）的一部分：联合电子设备工程委员会（Joint Electron Device Engineering Council，JEDEC）。该协会制定了一个制造商标识码的标准：&lt;a href=&#34;http://www.softnology.biz/pdf/JEP106AV.pdf&#34;&gt;Standard Manufacturer’s Identification Code&lt;/a&gt;，通过读取&lt;code&gt;mvendorid&lt;/code&gt;寄存器值，查阅该标准即可确定制造商。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;注：用 JEDEC 的话来说，Bank 编号比 Continuation 的数量大 1；因此，mvendorid Bank 字段编码的值比 JEDEC Bank 编号小一。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;注：以前，供应商 ID 是 RISC-V 基金会分配的编号，但这与 JEDEC 在维护制造商 ID 标准方面的工作重复。在撰写本文时，向 JEDEC 注册制造商 ID 的一次性费用为 500 美元。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;machine-mode-privileged-instructions&#34;&gt;Machine-Mode Privileged Instructions&lt;/h2&gt;
&lt;h3 id=&#34;environment-call-and-breakpoint&#34;&gt;Environment Call and Breakpoint&lt;/h3&gt;
&lt;h3 id=&#34;trap-return-instructions&#34;&gt;Trap-Return Instructions&lt;/h3&gt;
&lt;h3 id=&#34;wait-for-interrupt&#34;&gt;Wait for Interrupt&lt;/h3&gt;
&lt;p&gt;等待中断指令 (WFI) 为实现提供了一个提示，即当前的 hart 可以停止，直到需要服务中断。WFI 指令的执行也可以用来通知硬件平台合适的中断应该优先路由到这个 hart。WFI 在所有特权模式下都可用，并且可用于 U 模式 (可选地)。当 mstatus 中的 TW = 1 时，该指令可能会引发非法指令异常，如第 3.1.6.5 节所述。&lt;/p&gt;
&lt;p&gt;

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

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;如果在 hart 停止时存在或稍后出现启用的中断，则中断 trap 将在以下指令上执行，即在 trap 处理程序中恢复执行并且 &lt;code&gt;mepc = pc + 4&lt;/code&gt;。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h1 id="introduction">Introduction</h1>
<blockquote>
<p>Document Version 20211203</p>
</blockquote>
<h1 id="control-and-status-registers-csrs">Control and Status Registers (CSRs)</h1>
<h1 id="machine-level-isa-version-112">Machine-Level ISA, Version 1.12</h1>
<p>本章介绍了机器模式（M-mode）中可用的机器级操作，这是 RISC-V 系统中最高权限的模式。M 模式用于对硬件平台的低级访问，是复位时进入的第一个模式。M 模式也可以用来实现那些在硬件中直接实现过于困难或成本高昂的功能。RISC-V 的机器级 ISA 包含一个共同的核心，根据支持的其他权限级别和硬件实现的其他细节来扩展。</p>
<h2 id="machine-level-csrs">Machine-Level CSRs</h2>
<p>除了本节中描述的机器级 CSRs 外，M-mode 代码还可以访问较低特权级别的所有 CSRs。</p>
<h3 id="machine-isa-register-misa">Machine ISA Register <code>misa</code></h3>
<p>misa CSR 是 WARL 读写寄存器，报告硬件 (hart) 支持的 ISA。该寄存器在任何实现中都必须是可读的，但是可以返回零值以指示未实现 misa 寄存器，这就需要通过一个单独的非标准机制确定 CPU 功能。</p>
<p>

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>MXL（机器 XLEN）字段编码本机基本整数 ISA 宽度，如表 3.1 所示。MXL 字段在支持多个基本 ISA 宽度的实现中可能是可写的。M-mode 下的有效 XLEN, MXLEN，由 MXL 的设置给出，如果 misa 为零，则有一个固定的值。重置时，MXL 字段始终设置为最广泛支持的 ISA 变种。</p>
<p>

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>misa CSR 为 MXLEN 位宽。如果从 misa 读取的值不为零，该值的 MXL 字段总是表示当前的 MXLEN。如果对 misa 的写操作导致 MXLEN 发生更改，则 MXL 的位置将以新的宽度移动到 misa 的最高有效两位。</p>
<blockquote>
<p>可以使用返回的 misa 值的符号上的分支，以及可能在符号上左移一个分支和第二个分支，来快速确定基本宽度。这些检查可以用汇编代码编写，而无需知道机器的寄存器宽度（XLEN）。基本宽度由 XLEN = 2^(MXL + 4) 给出。如果 misa 为零，则可以通过将立即数 4 放置在一个寄存器中，然后一次将寄存器左移 31 位来找到基本宽度。如果在一次移位后为零，则该机器为 RV32。如果两次移位后为零，则机器为 RV64，否则为 RV128。</p>
</blockquote>
<p>Extensions 字段编码了目前存有的标准扩展，其每个 bit 都对应了字母表中的一个字母（bit 0 编码扩展“A”是否存在，bit 1 编码扩展“B”是否存在&hellip; 直至 bit 25 编码“Z”）。如果基础 ISA 是 RV32I、RV64I 或 RV128I，则置位“I”bit，否则如果基础 ISA 是 RV32E，则置位“E”bit。</p>
<p>Extensions 字段是一个能包含可写位的 WARL 字段（如果实现允许修改所支持的 ISA）。</p>
<p>复位（reset）时，Extensions 应包含所支持扩展的最大集，如果 E 和 I 都可用，则优先选择 I。</p>
<p>在通过清除 misa 中相应 bit 来禁止一个标准扩展时，由该扩展所定义或修改的指令和 CSR 将恢复为该扩展未实现时的定义，或者保留行为（revert to their defined or reserved behaviors as if the extension is not implemented）。</p>
<p>RV128 base ISA 的设计尚未完工，尽管预计本 specification 中大部分的剩余部分都将适用于 RV128，但本版本的文档仅关注 RV32 和 RV64。</p>
<p>如果支持用户模式（user mode），则将“U”bit 置位；如果支持主管模式（supervisor mode），则将“S”bit 置位。</p>
<p>如果存在任何非标准扩展（non-standard extensions），则将“X”bit 置位。</p>
<p>

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>“E”位是只读的。除非将 misa 硬连线为零，否则“E”位始终读取为“I”位的补码（补集？）。同时支持 RV32E 和 RV32I 的实现可以通过清除“I”位来选择 RV32E。</p>
<p>如果 ISA 功能 x 依赖 ISA 功能 y，则尝试启用功能 x 但禁用功能 y 会导致两个功能都被禁用。例如，设置“F” = 0 和“D” = 1 会导致同时清除“F”和“D”。</p>
<p>具体实现可能会在 2 或多个 misa 字段的集体设置上施加额外约束，此时将它们的集体看作是一个 WARL 字段。试图向其中写入一个不支持的组合会导致这些 bits 被置为某个支持的组合。</p>
<p>写 misa 可能会增加 IALIGN，例如，通过禁用 C 扩展。如果要写入 misa 的指令增加了 IALIGN，而后一条指令的地址未按 IALIGN 位对齐，则将抑制对 misa 的写入，从而使 misa 保持不变。</p>
<p>在软件启用一个之前被禁用的扩展时，除该扩展另有规定（specified），否则所有单独与该扩展有关的状态都将是未指定的（unspecified）。</p>
<h3 id="machine-vendor-id-register-mvendorid">Machine Vendor ID Register <code>mvendorid</code></h3>
<p><code>mvendorid</code> CSR 是一个 32 位只读寄存器，提供内核供应商的 JEDEC 制造商 ID。此寄存器在任何实现中都必须是可读的，但可以返回 0，表示该字段未实现或这是非商业实现。</p>
<p>

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>JEDEC 制造商 ID 通常编码为单字节连续的 <code>0x7f</code> 代码的序列，以不等于 <code>0x7f</code> 的单字节 ID 终止，并且在每个字节的最高有效位中带有奇校验位。<code>mvendorid</code> 在 Bank 字段中编码单字节的连续代码，并在 <code>Offset</code> 字段中编码最后一个字节，丢弃奇偶校验位。例如，JEDEC 制造商 ID <code>0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x7f 0x8a</code>（十二个连续代码，后跟 0x8a）将在 mvendorid 字段中编码为 <code>0x60a</code>。</p>
<blockquote>
<p>译者注：JEDEC 固态技术协会（JEDEC Solid State Technology Association）是固态及半导体工业界的一个标准化组织，它由约 300 家公司成员组成，约 3300 名技术人员通过 50 个不同的委员会运作，制定固态电子方面的工业标准。JEDEC 曾经是电子工业联盟（EIA）的一部分：联合电子设备工程委员会（Joint Electron Device Engineering Council，JEDEC）。该协会制定了一个制造商标识码的标准：<a href="http://www.softnology.biz/pdf/JEP106AV.pdf">Standard Manufacturer’s Identification Code</a>，通过读取<code>mvendorid</code>寄存器值，查阅该标准即可确定制造商。</p>
</blockquote>
<blockquote>
<p>注：用 JEDEC 的话来说，Bank 编号比 Continuation 的数量大 1；因此，mvendorid Bank 字段编码的值比 JEDEC Bank 编号小一。</p>
</blockquote>
<blockquote>
<p>注：以前，供应商 ID 是 RISC-V 基金会分配的编号，但这与 JEDEC 在维护制造商 ID 标准方面的工作重复。在撰写本文时，向 JEDEC 注册制造商 ID 的一次性费用为 500 美元。</p>
</blockquote>
<h2 id="machine-mode-privileged-instructions">Machine-Mode Privileged Instructions</h2>
<h3 id="environment-call-and-breakpoint">Environment Call and Breakpoint</h3>
<h3 id="trap-return-instructions">Trap-Return Instructions</h3>
<h3 id="wait-for-interrupt">Wait for Interrupt</h3>
<p>等待中断指令 (WFI) 为实现提供了一个提示，即当前的 hart 可以停止，直到需要服务中断。WFI 指令的执行也可以用来通知硬件平台合适的中断应该优先路由到这个 hart。WFI 在所有特权模式下都可用，并且可用于 U 模式 (可选地)。当 mstatus 中的 TW = 1 时，该指令可能会引发非法指令异常，如第 3.1.6.5 节所述。</p>
<p>

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

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

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

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

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

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

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

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

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="使用-virtio-scsi-磁盘">使用 virtio-scsi 磁盘</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl"><span class="nv">$WORK_DIR</span>/qemu/build/qemu-system-riscv64 -nographic <span class="se">\
</span></span></span><span class="line"><span class="cl">-machine virt,aclint<span class="o">=</span>on,aia<span class="o">=</span>aplic-imsic,acpi<span class="o">=</span>on -cpu rv64,ssofpmf<span class="o">=</span><span class="nb">true</span> -smp <span class="m">8</span>  -m 2G <span class="se">\
</span></span></span><span class="line"><span class="cl">-bios <span class="nv">$WORK_DIR</span>/opensbi/build/platform/generic/firmware/fw_jump.elf <span class="se">\
</span></span></span><span class="line"><span class="cl">-kernel <span class="nv">$WORK_DIR</span>/tianocore/Build/RiscvVirt/DEBUG_GCC5/FV/RISCVVIRT.fd  <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-scsi-pci,id<span class="o">=</span>scsi0,num_queues<span class="o">=</span><span class="m">4</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-device scsi-hd,drive<span class="o">=</span>drive0,bus<span class="o">=</span>scsi0.0,channel<span class="o">=</span>0,scsi-id<span class="o">=</span>0,lun<span class="o">=</span><span class="m">0</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span><span class="nv">$WORK_DIR</span>/buildroot/output/images/rootfs.cpio,format<span class="o">=</span>raw,if<span class="o">=</span>none,id<span class="o">=</span>drive0 <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-scsi-pci,id<span class="o">=</span>scsi1,num_queues<span class="o">=</span><span class="m">4</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-device scsi-hd,drive<span class="o">=</span>drive1,bus<span class="o">=</span>scsi0.0,channel<span class="o">=</span>0,scsi-id<span class="o">=</span>1,lun<span class="o">=</span><span class="m">0</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">-drive <span class="nv">file</span><span class="o">=</span><span class="nv">$WORK_DIR</span>/efi.img,format<span class="o">=</span>raw,if<span class="o">=</span>none,id<span class="o">=</span>drive1 <span class="se">\
</span></span></span><span class="line"><span class="cl">-device virtio-net-device,netdev<span class="o">=</span>usernet <span class="se">\
</span></span></span><span class="line"><span class="cl">-netdev user,id<span class="o">=</span>usernet,hostfwd<span class="o">=</span>tcp::9990-:22
</span></span></code></pre></div><p>At EFI Shell:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">Shell&gt; fs0:<span class="se">\I</span>mage <span class="nv">root</span><span class="o">=</span>/dev/sda <span class="nv">console</span><span class="o">=</span>ttyS0 rootwait earlycon
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>在 QEMU 上运行 64 位和 32 位 RISC-V-Linux</title>
      <link>https://lifeislife.cn/posts/qemu%E4%B8%8A%E8%BF%90%E8%A1%8C64%E4%BD%8D%E5%92%8C32%E4%BD%8Drisc-v-linux/</link>
      <pubDate>Wed, 28 Jul 2021 13:47:56 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/qemu%E4%B8%8A%E8%BF%90%E8%A1%8C64%E4%BD%8D%E5%92%8C32%E4%BD%8Drisc-v-linux/</guid>
      <description>&lt;h2 id=&#34;制作交叉工具链-riscv-gnu-toolchain&#34;&gt;制作交叉工具链 riscv-gnu-toolchain&lt;/h2&gt;
&lt;h3 id=&#34;下载源码&#34;&gt;下载源码&lt;/h3&gt;
&lt;p&gt;这个仓库是我遇到的最难下载的一个仓库了，公司网慢和虚拟机性能差都脱不了干系。估计下载了五小时都不止，刚开始还指望一个命令所有子模块都下载完的，结果愣是等了半天中断了。试了两次后放弃了。如果各位看官能一次完成，那您是福大。&lt;/p&gt;
&lt;p&gt;国内的码云平台有个&lt;a href=&#34;https://gitee.com/organizations/mirrors/projects&#34;&gt;Gitee 极速下载&lt;/a&gt;项目，上面有 GitHub 的一些常用开源项目的镜像，可供加速下载。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# riscv-gnu-toolchain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gitee&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mirrors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;riscv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;toolchain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下载时问题出现了，如果下载子模块仍然会卡住，如果不加&lt;code&gt;--recursive&lt;/code&gt;就只能下载主体内容，子模块都没有。（&lt;strong&gt;以下内容为第一安装时的方法，后续又找到了&lt;a href=&#34;&#34;&gt;git clone 快速下载子模块&lt;/a&gt;的方法&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;开始下载时不加&lt;code&gt;--recursive&lt;/code&gt;参数，只下载&lt;code&gt;riscv-gnu-toolchain&lt;/code&gt;的主体内容，然后进入到&lt;code&gt;riscv-gnu-toolchain&lt;/code&gt;文件夹下，手动下载子模块的内容。&lt;/p&gt;
&lt;p&gt;当下完&lt;code&gt;riscv-binutils&lt;/code&gt;继续下载&lt;code&gt;riscv-gdb&lt;/code&gt;时发现这两个项目是同一个项目，只是不同的分支。但是码云上并没有区分，但是我也没找到在码云上的对应分支。只能用油猴脚本了。&lt;/p&gt;
&lt;p&gt;如果你有油猴插件可以去&lt;a href=&#34;https://greasyfork.org/zh-CN&#34;&gt;greasyfork&lt;/a&gt;搜索安装&lt;strong&gt;GitHub 镜像访问，加速下载&lt;/strong&gt;这个脚本，刷新 GitHub 仓库界面就会多出几个镜像地址，一般下载都会快好几倍。如果不用油猴插件的可以用我复制好的链接。&lt;/p&gt;
&lt;p&gt;

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

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

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

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># riscv-binutils
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-binutils-gdb.git
</span></span><span class="line"><span class="cl"># riscv-gcc
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-gcc.git
</span></span><span class="line"><span class="cl"># riscv-dejagnu
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-dejagnu.git
</span></span><span class="line"><span class="cl"># riscv-glibc
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-glibc.git
</span></span><span class="line"><span class="cl"># riscv-newlib
</span></span><span class="line"><span class="cl">git clone https://gitee.com/mirrors/riscv-newlib.git
</span></span><span class="line"><span class="cl"># riscv-gdb
</span></span><span class="line"><span class="cl">git clone --depth=1 https://hub.fastgit.org/riscv/riscv-binutils-gdb.git
</span></span></code></pre></div><h3 id="编译-riscv-gnu-toolchain">编译 riscv-gnu-toolchain</h3>
<p>提前安装如下软件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">autoconf</span> <span class="n">automake</span> <span class="n">autotools</span><span class="o">-</span><span class="n">dev</span> <span class="n">curl</span> <span class="n">python3</span> <span class="n">libmpc</span><span class="o">-</span><span class="n">dev</span> <span class="n">libmpfr</span><span class="o">-</span><span class="n">dev</span> <span class="n">libgmp</span><span class="o">-</span><span class="n">dev</span> <span class="n">gawk</span> <span class="n">build</span><span class="o">-</span><span class="n">essential</span> <span class="n">bison</span> <span class="n">flex</span> <span class="n">texinfo</span> <span class="n">gperf</span> <span class="n">libtool</span> <span class="n">patchutils</span> <span class="n">bc</span> <span class="n">zlib1g</span><span class="o">-</span><span class="n">dev</span> <span class="n">libexpat</span><span class="o">-</span><span class="n">dev</span>
</span></span></code></pre></div><p>不听老人言，吃亏在眼前呀，本以为这是可选项，很多库都安装了，就没有操作这一步，结果就是编译半天结果还错了。如果报<code>make 错误 127</code>，那就老老实实把前置的这些库都装上。</p>
<p>建立<code>riscv-gnu-toolchain</code>安装目录<code>/opt/riscv64</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">./configure --prefix=/opt/riscv64 
</span></span><span class="line"><span class="cl">sudo make linux -j8
</span></span></code></pre></div><h3 id="导出安装路径">导出安装路径</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="k">export</span> <span class="n">PATH</span><span class="o">=</span><span class="s2">&#34;$PATH:/opt/riscv64/bin&#34;</span>
</span></span></code></pre></div><p>出现一下信息表示安装成功。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">Using</span> <span class="n">built</span><span class="o">-</span><span class="ow">in</span> <span class="n">specs</span><span class="o">.</span>
</span></span><span class="line"><span class="cl"><span class="n">COLLECT_GCC</span><span class="o">=</span><span class="n">riscv64</span><span class="o">-</span><span class="n">unknown</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">gnu</span><span class="o">-</span><span class="n">gcc</span>
</span></span><span class="line"><span class="cl"><span class="n">COLLECT_LTO_WRAPPER</span><span class="o">=/</span><span class="n">opt</span><span class="o">/</span><span class="n">riscv64</span><span class="o">/</span><span class="n">libexec</span><span class="o">/</span><span class="n">gcc</span><span class="o">/</span><span class="n">riscv64</span><span class="o">-</span><span class="n">unknown</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">gnu</span><span class="o">/</span><span class="mf">10.2</span><span class="o">.</span><span class="mi">0</span><span class="o">/</span><span class="n">lto</span><span class="o">-</span><span class="n">wrapper</span>
</span></span><span class="line"><span class="cl"><span class="n">Target</span><span class="p">:</span> <span class="n">riscv64</span><span class="o">-</span><span class="n">unknown</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">gnu</span>
</span></span><span class="line"><span class="cl"><span class="n">Configured</span> <span class="n">with</span><span class="p">:</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">dominic</span><span class="o">/</span><span class="n">riscv64</span><span class="o">-</span><span class="n">linux</span><span class="o">/</span><span class="n">riscv</span><span class="o">-</span><span class="n">gnu</span><span class="o">-</span><span class="n">toolchain</span><span class="o">/</span><span class="n">riscv</span><span class="o">-</span><span class="n">gcc</span><span class="o">/</span><span class="n">configure</span> <span class="o">--</span><span class="n">target</span><span class="o">=</span><span class="n">riscv64</span><span class="o">-</span><span class="n">unknown</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">gnu</span> <span class="o">--</span><span class="n">prefix</span><span class="o">=/</span><span class="n">opt</span><span class="o">/</span><span class="n">riscv64</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">sysroot</span><span class="o">=/</span><span class="n">opt</span><span class="o">/</span><span class="n">riscv64</span><span class="o">/</span><span class="n">sysroot</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">system</span><span class="o">-</span><span class="n">zlib</span> <span class="o">--</span><span class="n">enable</span><span class="o">-</span><span class="n">shared</span> <span class="o">--</span><span class="n">enable</span><span class="o">-</span><span class="n">tls</span> <span class="o">--</span><span class="n">enable</span><span class="o">-</span><span class="n">languages</span><span class="o">=</span><span class="n">c</span><span class="p">,</span><span class="n">c</span><span class="o">++</span><span class="p">,</span><span class="n">fortran</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">libmudflap</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">libssp</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">libquadmath</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">libsanitizer</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">nls</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">bootstrap</span> <span class="o">--</span><span class="n">src</span><span class="o">=.././</span><span class="n">riscv</span><span class="o">-</span><span class="n">gcc</span> <span class="o">--</span><span class="n">disable</span><span class="o">-</span><span class="n">multilib</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">abi</span><span class="o">=</span><span class="n">lp64d</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">arch</span><span class="o">=</span><span class="n">rv64imafdc</span> <span class="o">--</span><span class="n">with</span><span class="o">-</span><span class="n">tune</span><span class="o">=</span><span class="n">rocket</span> <span class="s1">&#39;CFLAGS_FOR_TARGET=-O2   -mcmodel=medlow&#39;</span> <span class="s1">&#39;CXXFLAGS_FOR_TARGET=-O2   -mcmodel=medlow&#39;</span>
</span></span><span class="line"><span class="cl"><span class="ne">Thread</span> <span class="n">model</span><span class="p">:</span> <span class="n">posix</span>
</span></span><span class="line"><span class="cl"><span class="n">Supported</span> <span class="n">LTO</span> <span class="n">compression</span> <span class="n">algorithms</span><span class="p">:</span> <span class="n">zlib</span>
</span></span><span class="line"><span class="cl"><span class="n">gcc</span> <span class="n">version</span> <span class="mf">10.2</span><span class="o">.</span><span class="mi">0</span> <span class="p">(</span><span class="n">GCC</span><span class="p">)</span> 
</span></span></code></pre></div><h2 id="制作内核">制作内核</h2>
<h3 id="下载-linux-内核">下载 Linux 内核</h3>
<p>makefile</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
