<?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>Kernel on 夜云泊</title>
    <link>https://lifeislife.cn/tags/kernel/</link>
    <description>feedId:57980998056508425+userId:73222296380546048 Recent content in Kernel on 夜云泊</description>
    <generator>Hugo -- 0.161.1</generator>
    <language>zh</language>
    <lastBuildDate>Sat, 13 Jan 2024 22:00:16 +0000</lastBuildDate>
    <atom:link href="https://lifeislife.cn/tags/kernel/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Linux内核模块校验机制</title>
      <link>https://lifeislife.cn/posts/linux%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97%E6%A0%A1%E9%AA%8C%E6%9C%BA%E5%88%B6/</link>
      <pubDate>Sat, 13 Jan 2024 22:00:16 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/linux%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97%E6%A0%A1%E9%AA%8C%E6%9C%BA%E5%88%B6/</guid>
      <description>&lt;p&gt;初学 Linux 内核或者第一次编译使用内核模块时经常会遇到类似这样的错误：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;insmod: ERROR: could not insert module kvm.ko: Invalid module format 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个报错通常由于当前插入&lt;code&gt;kvm.ko&lt;/code&gt;的&lt;code&gt;version magic&lt;/code&gt;版本信息与正在运行的 kernel 的&lt;code&gt;version magic&lt;/code&gt;版本不一致导致的。&lt;/p&gt;
&lt;h1 id=&#34;内核校验模块的流程&#34;&gt;内核校验模块的流程&lt;/h1&gt;
&lt;p&gt;我们从问题出发，看看内核是如何校验模块的。搜索了内核源码，找到了在函数&lt;code&gt;check_version&lt;/code&gt;中抛出了&lt;code&gt;disagrees about version of symbol&lt;/code&gt;错误信息，我们根据源码来回溯一下整个过程。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// kernel/module.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s32&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;Elf_Shdr&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sechdrs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sechdrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;versindex&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modversion_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* Exporting module didn&amp;#39;t supply crcs?  OK, we&amp;#39;re already tainted. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* No versions at all?  modprobe --force does this. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versindex&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;try_to_force_load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sechdrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versindex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh_addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;n&#34;&gt;num_versions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sechdrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versindex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sh_size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modversion_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num_versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;u32&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;strcmp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;IS_ENABLED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CONFIG_MODULE_REL_CRCS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;resolve_rel_crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;pr_debug&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;Found checksum %X vs module %lX&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;crcval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;goto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;bad_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* Broken toolchain. Warn once, then let it go.. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;nf&#34;&gt;pr_warn_once&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s: no symbol version for %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nl&#34;&gt;bad_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;nf&#34;&gt;pr_warn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s: disagrees about version of symbol %s&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参数说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;info: 包含正在加载信息的结构体。&lt;/li&gt;
&lt;li&gt;symname: 需要查找对比的符号的名称。&lt;/li&gt;
&lt;li&gt;mod: 表示模块的结构体。&lt;/li&gt;
&lt;li&gt;crc: 当前正在运行的内核的模块符号的 CRC（Cyclic Redundancy Check）值&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;如果 CRC 为空，不检查直接 PASS&lt;/li&gt;
&lt;li&gt;如果模块中没有_versions 小节，表示模块没有开启 CRC
&lt;ol&gt;
&lt;li&gt;如果开启了 CONFIG_MODULE_FORCE_LOAD，则强制加载，内核标记为 tainted，直接 PASS&lt;/li&gt;
&lt;li&gt;如果没有开启 CONFIG_MODULE_FORCE_LOAD，则报错&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;如果模块中有_versions 小节，没有找到 module_layout 符号，报 warning，直接 PASS&lt;/li&gt;
&lt;li&gt;如果模块中有_versions 小节，找到 module_layout 符号
&lt;ol&gt;
&lt;li&gt;对比_versions 小节中的 CRC 和参数中的 CRC，如果一致，PASS&lt;/li&gt;
&lt;li&gt;如果不一致，报错&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;插播一句，CRC是什么？在 Linux 内核中，模块符号 CRC（Cyclic Redundancy Check）是一种校验值，用于确保模块中的符号（函数、变量等）在加载时与内核中的符号一致。当模块被构建时，针对每个符号都会计算一个 CRC 值，然后将这些 CRC 值保存在模块的符号版本表中。简单理解就是如果要保持CRC不变，需要满足两个条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;语法保持不变
遵守这个条件，说明如果模块在新内核下重新编译，那应该没有任何语法问题。 即导出符号的类型名没有变化，如果是函数，则要求参数和返回值类型没有任何变化；如果这些类型是结构体的话，结构体的成员名也没有有任何变化。&lt;/li&gt;
&lt;li&gt;语义保持不变
这要求符号的类型不能有变化，如果类型本身是结构体(struct)，则它成员的类型不能有变化，成员在结构体内的位置不能有变化，以及成员本身不能增删。
如果想要深入了解如何计算CRC可以参考这篇博客：&lt;a href=&#34;https://blog.csdn.net/linyt/article/details/42559639&#34;&gt;Linux内核模块符号CRC检查机制-CSDN博客&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;分析代码我们可以知道，内核会通过遍历正在加载的模块的版本信息的数组&lt;code&gt;versions&lt;/code&gt;，从中查找与给定符号名称匹配的版本信息。如果找到匹配的版本信息，则计算 CRC 值，与参数中的 CRC 值进行比较。（通过后续分析我们知道参数的 CRC 就是正在运行的内核的 module_layout 符号的 CRC）如果匹配，表示版本一致，返回 1。如果不匹配，打印调试信息，并跳转到 &lt;code&gt;bad_version&lt;/code&gt;，输出警告信息。&lt;/p&gt;
&lt;p&gt;这里有两个疑问，&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;versions&lt;/code&gt; 内容是怎么链接到模块的 elf 文件中的？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们找到模块的&lt;code&gt;mod.c&lt;/code&gt;文件，打开可以发现以下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;MODULE_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vermagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;VERMAGIC_STRING&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;MODULE_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KBUILD_MODNAME&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;__visible&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;__this_module&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;__section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gnu&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;linkonce&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;this_module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;KBUILD_MODNAME&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;init&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;init_module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_MODULE_UNLOAD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cleanup_module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arch&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MODULE_ARCH_INIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_RETPOLINE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;MODULE_INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;retpoline&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Y&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modversion_info&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;____versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;__used&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;__section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;__versions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x3e549f1d&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;module_layout&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x5138e6ba&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;param_ops_int&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x183b57f9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;phy_ethtool_nway_reset&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x6e5363eb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;eth_validate_addr&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x4df55e5b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;usb_deregister&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;0x8e48f69b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;usb_register_driver&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个文件是在编译过程中调用了&lt;code&gt;scripts/modpost&lt;/code&gt;脚本生成的，它的功能是在里面增加了 2 个&lt;code&gt;__section&lt;/code&gt;，&lt;code&gt;.gnu.linkonce.this_module&lt;/code&gt;和&lt;code&gt;__versions&lt;/code&gt;。__versions 小节的内容就是一些字符串和值组成的数组，&lt;code&gt;check_version&lt;/code&gt;就是解析这个小节去做验证。&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;CRC 值哪来的？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们继续向上跟踪，找到函数&lt;code&gt;check_modstruct_version&lt;/code&gt;，其中&lt;code&gt;find_symbol&lt;/code&gt;会在内核符号表中查找给定符号名称的符号信息，接着调用&lt;code&gt;check_version&lt;/code&gt;函数，传入符号名称、模块结构体和 CRC 值，进行版本匹配。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// kernel/module.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;inline&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_modstruct_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s32&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;  * Since this should be found in kernel (which can&amp;#39;t be removed), no
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;  * locking is necessary -- use preempt_disable() to placate lockdep.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;  */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;nf&#34;&gt;preempt_disable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;find_symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;module_layout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;preempt_enable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;BUG&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;nf&#34;&gt;preempt_enable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;module_layout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 获取当前运行内核 module_layout 函数的 crc 值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;find_symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;module_layout&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;crc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;each_symbol_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find_exported_symbol_in_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;fsa&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 遍历内核三个导出符号表段__start___ksymtab，__start___ksymtab_gpl 和__start___ksymtab_gpl_future，为每段调用 find_symbol_in_section
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;each_symbol_in_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ARRAY_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 遍历内核每个已加载模块的三个导出符号表段 mod-&amp;gt;syms,mod-&amp;gt;gpl_syms,mod-&amp;gt;gpl_future_syms，为每段调用 find_symbol_in_section
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;each_symbol_in_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;ARRAY_SIZE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;arr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// 对导出符号表进行二分查找，按照字符串排序，符号表的地址按照地址排序
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nf&#34;&gt;find_exported_symbol_in_section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symsearch&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;syms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;owner&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Linux 对可装载模块采取了两层验证&lt;/strong&gt;：除了上述的模块 CRC 值校验外还有 &lt;code&gt;vermagic&lt;/code&gt; 的检查。模块 vermagic（即 Version Magic String）保存了模块编译时的内核版本以及 SMP 等配置信息，当模块 vermagic 与主机信息不相符时也无法加载模块。&lt;/p&gt;
&lt;p&gt;在内核中&lt;code&gt;load_module&lt;/code&gt;函数调用&lt;code&gt;check_modstruct_version&lt;/code&gt;函数完成 CRC 校验后，就会继续调用&lt;code&gt;layout_and_allocate --&amp;gt; check_modinfo&lt;/code&gt; 完成 vermagic 校验。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// kernel/module.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_modinfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;load_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;get_modinfo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;vermagic&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;MODULE_INIT_IGNORE_VERMAGIC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;cm&#34;&gt;/* This is allowed: modprobe --force will invalidate it. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;try_to_force_load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;bad vermagic&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;same_magic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vermagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nf&#34;&gt;pr_err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;%s: version magic &amp;#39;%s&amp;#39; should be &amp;#39;%s&amp;#39;&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modmagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vermagic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ENOEXEC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;get_modinfo&lt;/code&gt; 会获取内核中的 vermagic 信息，模块 vermagic 信息则被保存在了 ELF 的 &lt;code&gt;.modinfo&lt;/code&gt; 小节中。这里我们说的 vermagic 就是下文提到的拓展版本信息，它就是系统配置信息组成的一个字符串。&lt;/p&gt;
&lt;h1 id=&#34;如何解决模块校验错误&#34;&gt;如何解决模块校验错误&lt;/h1&gt;
&lt;p&gt;Linux 对可装载模块采取了两层验证，我们需要分别从 CRC 和 vermagic 两个方面来解决模块校验错误。首先从简单的 vermagic 校验开始。我们需要保证运行的内核版本与模块编译时的内核版本一致，这样才能保证 vermagic 校验通过。首先了解如何查看内核版本以及模块版本信息，然后修改内核模块版本信息。&lt;/p&gt;
&lt;h2 id=&#34;解决-vermagic-校验错误&#34;&gt;解决 vermagic 校验错误&lt;/h2&gt;
&lt;h3 id=&#34;如何查看内核版本以及模块版本信息&#34;&gt;如何查看内核版本以及模块版本信息&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;uname&lt;/code&gt;参数功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-s, 输出 kernel 名称；&lt;/li&gt;
&lt;li&gt;-n, 输出主机名；&lt;/li&gt;
&lt;li&gt;-r, 输出 kernel 发行版本号；&lt;/li&gt;
&lt;li&gt;-v, 输出操作系统版本；&lt;/li&gt;
&lt;li&gt;-m, 输出主机的硬件架构名称；&lt;/li&gt;
&lt;li&gt;-p, 输出处理器类型；&lt;/li&gt;
&lt;li&gt;-i, 输出硬件平台；&lt;/li&gt;
&lt;li&gt;-o, 输出操作系统名称&lt;/li&gt;
&lt;li&gt;-a, 输出所有信息&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输出kernel发行版本号&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uname -r
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6.4.0-10.1.0.20.oe2309.riscv64
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 输出所有信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uname -a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Linux openeuler 6.4.0-10.1.0.20.oe2309.riscv64 &lt;span class=&#34;c1&#34;&gt;#1 SMP Sat Oct  7 06:19:28 UTC 2023 riscv64 riscv64 riscv64 GNU/Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;modinfo 可以查看模块信息，包括模块vermagic信息。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;modinfo kvm.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;filename:       /root/build-kernel/kernel/./arch/riscv/kvm/kvm.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;license:        GPL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;author:         Qumranet
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;srcversion:     5DA13DC0E55100B5FE1D56A
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;depends:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;intree:         Y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;name:           kvm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vermagic:       6.4.0 SMP mod_unload modversions riscv
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parm:           halt_poll_ns:uint
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parm:           halt_poll_ns_grow:uint
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parm:           halt_poll_ns_grow_start:uint
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;parm:           halt_poll_ns_shrink:uint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中&lt;code&gt;vermagic&lt;/code&gt;就是&lt;code&gt;version magic&lt;/code&gt;版本信息，可以看到当前&lt;code&gt;kvm.ko&lt;/code&gt;的&lt;code&gt;version magic&lt;/code&gt;版本信息为&lt;code&gt;6.4.0&lt;/code&gt;。与前文的&lt;code&gt;uname -r&lt;/code&gt;输出的 kernel 发行版本号&lt;code&gt;6.4.0-10.1.0.20.oe2309.riscv64&lt;/code&gt;不一致。所以会报错。&lt;/p&gt;
&lt;h3 id=&#34;修改内核模块版本信息&#34;&gt;修改内核模块版本信息&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;修改基础版本信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;打开内核源代码根目录下的 Makefile 文件。你会找到一个包含内核版本信息的地方，类似于：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-Makefile&#34; data-lang=&#34;Makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# SPDX-License-Identifier: GPL-2.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;VERSION&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;PATCHLEVEL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;SUBLEVEL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;EXTRAVERSION&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;表示内核版基础本号为&lt;code&gt;6.4.0&lt;/code&gt;。&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;修改拓展版本信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;kernel 引入了一些配置来增强版本信息，在内核源码的&lt;code&gt;&amp;quot;include/linux/vermagic.h&amp;quot;&lt;/code&gt;下我们可以看到模块的健全版本信息，如下默认配置的有：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* Simply sanity version stamp for modules. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_SMP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_SMP &amp;#34;SMP &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_SMP &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_PREEMPT_BUILD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_PREEMPT &amp;#34;preempt &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#elif defined(CONFIG_PREEMPT_RT)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_PREEMPT &amp;#34;preempt_rt &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_PREEMPT &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_MODULE_UNLOAD
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_MODULE_UNLOAD &amp;#34;mod_unload &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_MODULE_UNLOAD &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef CONFIG_MODVERSIONS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_MODVERSIONS &amp;#34;modversions &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_VERMAGIC_MODVERSIONS &amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#ifdef RANDSTRUCT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;generated/randstruct_hash.h&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_RANDSTRUCT &amp;#34;RANDSTRUCT_&amp;#34; RANDSTRUCT_HASHED_SEED
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define MODULE_RANDSTRUCT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#define VERMAGIC_STRING                                                 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        UTS_RELEASE &amp;#34; &amp;#34;                                                 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                     \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS       \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MODULE_ARCH_VERMAGIC                                            \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;        MODULE_RANDSTRUCT
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，&lt;code&gt;&amp;quot;UTS_RELEASE&amp;quot;&lt;/code&gt;的配置在内核源码的&lt;code&gt;&amp;quot;include/generated/utsrelease.h&amp;quot;&lt;/code&gt;下可以看到，&lt;code&gt;utsrelease.h&lt;/code&gt;的内容是由&lt;code&gt;Makefile&lt;/code&gt;和``.config&lt;code&gt;的内容来生成的，当成功编译kernel以后，&lt;/code&gt;utsrelease.h`得到更新，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#defineUTS_RELEASE &amp;#34;6.4.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么前文&amp;quot;6.4.0-d46299ae&amp;quot;中的&amp;quot;-d46299ae&amp;quot;是如何得来的呢？其实这个是开发者使用了 Git 来管理代码。当你修改或者提交代码以后，每次编译内核后，在&amp;quot;UTS_RELEASE&amp;quot;后面就会看到一串哈希值，例如&amp;quot;6.4.0-d46299ae&amp;quot;，其中&amp;quot;-d46299ae&amp;quot;这个就是 Git 版本控制而产生的哈希值。发行版本号只是各个厂商用于区别自己发布的不同时期的 kernel 版本或者产品版本而产生的编号，完全由各厂商自己定义。&lt;/p&gt;
&lt;h2 id=&#34;解决-crc-校验错误&#34;&gt;解决 CRC 校验错误&lt;/h2&gt;
&lt;p&gt;我们可以通过一些手段修改新模块的 module_layout 的 CRC 与内核CRC相同，再插入。&lt;code&gt;/boot&lt;/code&gt;目录下通常有个在&lt;code&gt;symvers-&amp;lt;kernel_version&amp;gt;.gz&lt;/code&gt; 文件通常包含了内核模块的符号版本信息。这个文件是由 Linux 内核构建时生成的，用于记录在该内核版本下构建的模块的符号信息，包括函数和变量的名称、版本号等。里面就保存了内核的 module_layout 的 CRC 值。我们可以使用&lt;code&gt;gzip -d&lt;/code&gt;命令解压这个文件，找到 module_layout 的 CRC 值，记录下来。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;方法一：使用 16 进制编辑器修改模块文件，将 module_layout 的值修改为相同的值，再插入。
在 Linux 中，可以使用 &lt;code&gt;hexdump&lt;/code&gt; 和 &lt;code&gt;xxd&lt;/code&gt; 等工具查看二进制文件的内容，并尝试编辑。下面是一种使用 &lt;code&gt;xxd&lt;/code&gt; 查看和修改二进制文件的方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;使用 &lt;code&gt;xxd&lt;/code&gt; 将二进制文件转换为十六进制文本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xxd /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko &amp;gt; kvm_hex.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这将创建一个名为 &lt;code&gt;kvm_hex.txt&lt;/code&gt; 的文本文件，其中包含 &lt;code&gt;kvm.ko&lt;/code&gt; 的十六进制表示。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用文本编辑器（如 &lt;code&gt;nano&lt;/code&gt; 或 &lt;code&gt;vim&lt;/code&gt;）打开 &lt;code&gt;kvm_hex.txt&lt;/code&gt;，找到并编辑 &lt;code&gt;module_layout&lt;/code&gt; 的值。请确保你了解所做更改的含义，并且只修改你确信的内容。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;保存并关闭文本编辑器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 &lt;code&gt;xxd&lt;/code&gt; 将修改后的十六进制文本转换回二进制文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;xxd -r kvm_hex.txt &amp;gt; /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这将覆盖原始的 &lt;code&gt;kvm.ko&lt;/code&gt; 文件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;方法二：修改 Module.symvers&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 清理编译结果。不要使用 make distclean，这会删除.config 文件以及 Module.symvers 文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make clean
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 修改 Module.symvers 文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sed -i  &lt;span class=&#34;s1&#34;&gt;&amp;#39;/module_layout/ s/0x[0-9a-f][0-9a-f]*/0xdf88831e/&amp;#39;&lt;/span&gt; Module.symvers
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 重新编译模块&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;M&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./arch/riscv/kvm/ -j33
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 检查模块的 module_layout&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;modprobe --dump-modversions /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep module_layout
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0xdf88831e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;如何生成-modc-文件&#34;&gt;如何生成 .mod.c 文件&lt;/h1&gt;
&lt;p&gt;如果是自己写的模块，可以根据下面的命令编译模块，就可以得到&lt;code&gt;.mod.c&lt;/code&gt;文件，它是源文件到&lt;code&gt;.mod.o&lt;/code&gt;文件的一个中间文件。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make -C /root/build-kernel/kernel &lt;span class=&#34;nv&#34;&gt;M&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/driver_study/ modules -j22
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果是用内核自己的模块，执行&lt;code&gt;make modules&lt;/code&gt;命令，也可以得到&lt;code&gt;.mod.c&lt;/code&gt;文件。但是一般执行&lt;code&gt;make -j22&lt;/code&gt;命令就不会生成这些文件，我们可以找一个启用的内核模块，例如&lt;code&gt;kvm.ko&lt;/code&gt;，执行下面的命令，就可以得到&lt;code&gt;.mod.c&lt;/code&gt;文件。不能随便找个模块，必须在 config 中开启的模块，否则会报错&lt;code&gt;undefined!&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make  &lt;span class=&#34;nv&#34;&gt;M&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;./arch/riscv/kvm modules -j22
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<p>初学 Linux 内核或者第一次编译使用内核模块时经常会遇到类似这样的错误：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">insmod: ERROR: could not insert module kvm.ko: Invalid module format 
</span></span></code></pre></div><p>这个报错通常由于当前插入<code>kvm.ko</code>的<code>version magic</code>版本信息与正在运行的 kernel 的<code>version magic</code>版本不一致导致的。</p>
<h1 id="内核校验模块的流程">内核校验模块的流程</h1>
<p>我们从问题出发，看看内核是如何校验模块的。搜索了内核源码，找到了在函数<code>check_version</code>中抛出了<code>disagrees about version of symbol</code>错误信息，我们根据源码来回溯一下整个过程。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// kernel/module.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">check_version</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">load_info</span> <span class="o">*</span><span class="n">info</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">symname</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">mod</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">const</span> <span class="n">s32</span> <span class="o">*</span><span class="n">crc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Elf_Shdr</span> <span class="o">*</span><span class="n">sechdrs</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">sechdrs</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">versindex</span> <span class="o">=</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">index</span><span class="p">.</span><span class="n">vers</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">num_versions</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="k">struct</span> <span class="n">modversion_info</span> <span class="o">*</span><span class="n">versions</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/* Exporting module didn&#39;t supply crcs?  OK, we&#39;re already tainted. */</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">crc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/* No versions at all?  modprobe --force does this. */</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">versindex</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nf">try_to_force_load</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="n">symname</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">versions</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span> <span class="n">sechdrs</span><span class="p">[</span><span class="n">versindex</span><span class="p">].</span><span class="n">sh_addr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="n">num_versions</span> <span class="o">=</span> <span class="n">sechdrs</span><span class="p">[</span><span class="n">versindex</span><span class="p">].</span><span class="n">sh_size</span>
</span></span><span class="line"><span class="cl">  <span class="o">/</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">modversion_info</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">num_versions</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">u32</span> <span class="n">crcval</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nf">strcmp</span><span class="p">(</span><span class="n">versions</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">name</span><span class="p">,</span> <span class="n">symname</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nf">IS_ENABLED</span><span class="p">(</span><span class="n">CONFIG_MODULE_REL_CRCS</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">   <span class="n">crcval</span> <span class="o">=</span> <span class="nf">resolve_rel_crc</span><span class="p">(</span><span class="n">crc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="cl">   <span class="n">crcval</span> <span class="o">=</span> <span class="o">*</span><span class="n">crc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="n">versions</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">crc</span> <span class="o">==</span> <span class="n">crcval</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pr_debug</span><span class="p">(</span><span class="s">&#34;Found checksum %X vs module %lX</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">crcval</span><span class="p">,</span> <span class="n">versions</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">crc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">goto</span> <span class="n">bad_version</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/* Broken toolchain. Warn once, then let it go.. */</span>
</span></span><span class="line"><span class="cl"> <span class="nf">pr_warn_once</span><span class="p">(</span><span class="s">&#34;%s: no symbol version for %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">symname</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nl">bad_version</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="nf">pr_warn</span><span class="p">(</span><span class="s">&#34;%s: disagrees about version of symbol %s</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="n">info</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">symname</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>参数说明：</p>
<ul>
<li>info: 包含正在加载信息的结构体。</li>
<li>symname: 需要查找对比的符号的名称。</li>
<li>mod: 表示模块的结构体。</li>
<li>crc: 当前正在运行的内核的模块符号的 CRC（Cyclic Redundancy Check）值</li>
</ul>
<ol>
<li>如果 CRC 为空，不检查直接 PASS</li>
<li>如果模块中没有_versions 小节，表示模块没有开启 CRC
<ol>
<li>如果开启了 CONFIG_MODULE_FORCE_LOAD，则强制加载，内核标记为 tainted，直接 PASS</li>
<li>如果没有开启 CONFIG_MODULE_FORCE_LOAD，则报错</li>
</ol>
</li>
<li>如果模块中有_versions 小节，没有找到 module_layout 符号，报 warning，直接 PASS</li>
<li>如果模块中有_versions 小节，找到 module_layout 符号
<ol>
<li>对比_versions 小节中的 CRC 和参数中的 CRC，如果一致，PASS</li>
<li>如果不一致，报错</li>
</ol>
</li>
</ol>
<blockquote>
<p>插播一句，CRC是什么？在 Linux 内核中，模块符号 CRC（Cyclic Redundancy Check）是一种校验值，用于确保模块中的符号（函数、变量等）在加载时与内核中的符号一致。当模块被构建时，针对每个符号都会计算一个 CRC 值，然后将这些 CRC 值保存在模块的符号版本表中。简单理解就是如果要保持CRC不变，需要满足两个条件：</p>
<ol>
<li>语法保持不变
遵守这个条件，说明如果模块在新内核下重新编译，那应该没有任何语法问题。 即导出符号的类型名没有变化，如果是函数，则要求参数和返回值类型没有任何变化；如果这些类型是结构体的话，结构体的成员名也没有有任何变化。</li>
<li>语义保持不变
这要求符号的类型不能有变化，如果类型本身是结构体(struct)，则它成员的类型不能有变化，成员在结构体内的位置不能有变化，以及成员本身不能增删。
如果想要深入了解如何计算CRC可以参考这篇博客：<a href="https://blog.csdn.net/linyt/article/details/42559639">Linux内核模块符号CRC检查机制-CSDN博客</a></li>
</ol>
</blockquote>
<p>分析代码我们可以知道，内核会通过遍历正在加载的模块的版本信息的数组<code>versions</code>，从中查找与给定符号名称匹配的版本信息。如果找到匹配的版本信息，则计算 CRC 值，与参数中的 CRC 值进行比较。（通过后续分析我们知道参数的 CRC 就是正在运行的内核的 module_layout 符号的 CRC）如果匹配，表示版本一致，返回 1。如果不匹配，打印调试信息，并跳转到 <code>bad_version</code>，输出警告信息。</p>
<p>这里有两个疑问，</p>
<ol>
<li><code>versions</code> 内容是怎么链接到模块的 elf 文件中的？</li>
</ol>
<p>我们找到模块的<code>mod.c</code>文件，打开可以发现以下内容：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="nf">MODULE_INFO</span><span class="p">(</span><span class="n">vermagic</span><span class="p">,</span> <span class="n">VERMAGIC_STRING</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="nf">MODULE_INFO</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">KBUILD_MODNAME</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">__visible</span> <span class="k">struct</span> <span class="n">module</span> <span class="n">__this_module</span>
</span></span><span class="line"><span class="cl"><span class="nf">__section</span><span class="p">(.</span><span class="n">gnu</span><span class="p">.</span><span class="n">linkonce</span><span class="p">.</span><span class="n">this_module</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">KBUILD_MODNAME</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">init</span> <span class="o">=</span> <span class="n">init_module</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_MODULE_UNLOAD
</span></span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">exit</span> <span class="o">=</span> <span class="n">cleanup_module</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"> <span class="p">.</span><span class="n">arch</span> <span class="o">=</span> <span class="n">MODULE_ARCH_INIT</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_RETPOLINE
</span></span></span><span class="line"><span class="cl"><span class="nf">MODULE_INFO</span><span class="p">(</span><span class="n">retpoline</span><span class="p">,</span> <span class="s">&#34;Y&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">modversion_info</span> <span class="n">____versions</span><span class="p">[]</span>
</span></span><span class="line"><span class="cl"><span class="n">__used</span> <span class="nf">__section</span><span class="p">(</span><span class="n">__versions</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x3e549f1d</span><span class="p">,</span> <span class="s">&#34;module_layout&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x5138e6ba</span><span class="p">,</span> <span class="s">&#34;param_ops_int&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x183b57f9</span><span class="p">,</span> <span class="s">&#34;phy_ethtool_nway_reset&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x6e5363eb</span><span class="p">,</span> <span class="s">&#34;eth_validate_addr&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x4df55e5b</span><span class="p">,</span> <span class="s">&#34;usb_deregister&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="mh">0x8e48f69b</span><span class="p">,</span> <span class="s">&#34;usb_register_driver&#34;</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这个文件是在编译过程中调用了<code>scripts/modpost</code>脚本生成的，它的功能是在里面增加了 2 个<code>__section</code>，<code>.gnu.linkonce.this_module</code>和<code>__versions</code>。__versions 小节的内容就是一些字符串和值组成的数组，<code>check_version</code>就是解析这个小节去做验证。</p>
<ol start="2">
<li>CRC 值哪来的？</li>
</ol>
<p>我们继续向上跟踪，找到函数<code>check_modstruct_version</code>，其中<code>find_symbol</code>会在内核符号表中查找给定符号名称的符号信息，接着调用<code>check_version</code>函数，传入符号名称、模块结构体和 CRC 值，进行版本匹配。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// kernel/module.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kr">inline</span> <span class="kt">int</span> <span class="nf">check_modstruct_version</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">load_info</span> <span class="o">*</span><span class="n">info</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">       <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">mod</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="n">s32</span> <span class="o">*</span><span class="n">crc</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">  * Since this should be found in kernel (which can&#39;t be removed), no
</span></span></span><span class="line"><span class="cl"><span class="cm">  * locking is necessary -- use preempt_disable() to placate lockdep.
</span></span></span><span class="line"><span class="cl"><span class="cm">  */</span>
</span></span><span class="line"><span class="cl"> <span class="nf">preempt_disable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">find_symbol</span><span class="p">(</span><span class="s">&#34;module_layout&#34;</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">crc</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span> <span class="nb">false</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">preempt_enable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="nf">BUG</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nf">preempt_enable</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nf">check_version</span><span class="p">(</span><span class="n">info</span><span class="p">,</span> <span class="s">&#34;module_layout&#34;</span><span class="p">,</span> <span class="n">mod</span><span class="p">,</span> <span class="n">crc</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// 获取当前运行内核 module_layout 函数的 crc 值
</span></span></span><span class="line"><span class="cl"><span class="nf">find_symbol</span><span class="p">(</span><span class="s">&#34;module_layout&#34;</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">crc</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span> <span class="nb">false</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nf">each_symbol_section</span><span class="p">(</span><span class="n">find_exported_symbol_in_section</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fsa</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 遍历内核三个导出符号表段__start___ksymtab，__start___ksymtab_gpl 和__start___ksymtab_gpl_future，为每段调用 find_symbol_in_section
</span></span></span><span class="line"><span class="cl">        <span class="nf">each_symbol_in_section</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="nf">ARRAY_SIZE</span><span class="p">(</span><span class="n">arr</span><span class="p">),</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">fn</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// 遍历内核每个已加载模块的三个导出符号表段 mod-&gt;syms,mod-&gt;gpl_syms,mod-&gt;gpl_future_syms，为每段调用 find_symbol_in_section
</span></span></span><span class="line"><span class="cl">        <span class="nf">each_symbol_in_section</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="nf">ARRAY_SIZE</span><span class="p">(</span><span class="n">arr</span><span class="p">),</span> <span class="n">mod</span><span class="p">,</span> <span class="n">fn</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// 对导出符号表进行二分查找，按照字符串排序，符号表的地址按照地址排序
</span></span></span><span class="line"><span class="cl">            <span class="nf">find_exported_symbol_in_section</span><span class="p">(</span><span class="k">const</span> <span class="k">struct</span> <span class="n">symsearch</span> <span class="o">*</span><span class="n">syms</span><span class="p">,</span><span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">,</span><span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
</span></span></code></pre></div><p><strong>Linux 对可装载模块采取了两层验证</strong>：除了上述的模块 CRC 值校验外还有 <code>vermagic</code> 的检查。模块 vermagic（即 Version Magic String）保存了模块编译时的内核版本以及 SMP 等配置信息，当模块 vermagic 与主机信息不相符时也无法加载模块。</p>
<p>在内核中<code>load_module</code>函数调用<code>check_modstruct_version</code>函数完成 CRC 校验后，就会继续调用<code>layout_and_allocate --&gt; check_modinfo</code> 完成 vermagic 校验。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// kernel/module.c
</span></span></span><span class="line"><span class="cl"><span class="k">static</span> <span class="kt">int</span> <span class="nf">check_modinfo</span><span class="p">(</span><span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">mod</span><span class="p">,</span> <span class="k">struct</span> <span class="n">load_info</span> <span class="o">*</span><span class="n">info</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">modmagic</span> <span class="o">=</span> <span class="nf">get_modinfo</span><span class="p">(</span><span class="n">info</span><span class="p">,</span> <span class="s">&#34;vermagic&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="kt">int</span> <span class="n">err</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">MODULE_INIT_IGNORE_VERMAGIC</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">modmagic</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="cm">/* This is allowed: modprobe --force will invalidate it. */</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">modmagic</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="n">err</span> <span class="o">=</span> <span class="nf">try_to_force_load</span><span class="p">(</span><span class="n">mod</span><span class="p">,</span> <span class="s">&#34;bad vermagic&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="n">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="n">err</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nf">same_magic</span><span class="p">(</span><span class="n">modmagic</span><span class="p">,</span> <span class="n">vermagic</span><span class="p">,</span> <span class="n">info</span><span class="o">-&gt;</span><span class="n">index</span><span class="p">.</span><span class="n">vers</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nf">pr_err</span><span class="p">(</span><span class="s">&#34;%s: version magic &#39;%s&#39; should be &#39;%s&#39;</span><span class="se">\n</span><span class="s">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">         <span class="n">info</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">modmagic</span><span class="p">,</span> <span class="n">vermagic</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="o">-</span><span class="n">ENOEXEC</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>get_modinfo</code> 会获取内核中的 vermagic 信息，模块 vermagic 信息则被保存在了 ELF 的 <code>.modinfo</code> 小节中。这里我们说的 vermagic 就是下文提到的拓展版本信息，它就是系统配置信息组成的一个字符串。</p>
<h1 id="如何解决模块校验错误">如何解决模块校验错误</h1>
<p>Linux 对可装载模块采取了两层验证，我们需要分别从 CRC 和 vermagic 两个方面来解决模块校验错误。首先从简单的 vermagic 校验开始。我们需要保证运行的内核版本与模块编译时的内核版本一致，这样才能保证 vermagic 校验通过。首先了解如何查看内核版本以及模块版本信息，然后修改内核模块版本信息。</p>
<h2 id="解决-vermagic-校验错误">解决 vermagic 校验错误</h2>
<h3 id="如何查看内核版本以及模块版本信息">如何查看内核版本以及模块版本信息</h3>
<p><code>uname</code>参数功能：</p>
<ul>
<li>-s, 输出 kernel 名称；</li>
<li>-n, 输出主机名；</li>
<li>-r, 输出 kernel 发行版本号；</li>
<li>-v, 输出操作系统版本；</li>
<li>-m, 输出主机的硬件架构名称；</li>
<li>-p, 输出处理器类型；</li>
<li>-i, 输出硬件平台；</li>
<li>-o, 输出操作系统名称</li>
<li>-a, 输出所有信息</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 输出kernel发行版本号</span>
</span></span><span class="line"><span class="cl">uname -r
</span></span><span class="line"><span class="cl">6.4.0-10.1.0.20.oe2309.riscv64
</span></span><span class="line"><span class="cl"><span class="c1"># 输出所有信息</span>
</span></span><span class="line"><span class="cl">uname -a
</span></span><span class="line"><span class="cl">Linux openeuler 6.4.0-10.1.0.20.oe2309.riscv64 <span class="c1">#1 SMP Sat Oct  7 06:19:28 UTC 2023 riscv64 riscv64 riscv64 GNU/Linux</span>
</span></span></code></pre></div><p>modinfo 可以查看模块信息，包括模块vermagic信息。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">modinfo kvm.ko
</span></span><span class="line"><span class="cl">filename:       /root/build-kernel/kernel/./arch/riscv/kvm/kvm.ko
</span></span><span class="line"><span class="cl">license:        GPL
</span></span><span class="line"><span class="cl">author:         Qumranet
</span></span><span class="line"><span class="cl">srcversion:     5DA13DC0E55100B5FE1D56A
</span></span><span class="line"><span class="cl">depends:
</span></span><span class="line"><span class="cl">intree:         Y
</span></span><span class="line"><span class="cl">name:           kvm
</span></span><span class="line"><span class="cl">vermagic:       6.4.0 SMP mod_unload modversions riscv
</span></span><span class="line"><span class="cl">parm:           halt_poll_ns:uint
</span></span><span class="line"><span class="cl">parm:           halt_poll_ns_grow:uint
</span></span><span class="line"><span class="cl">parm:           halt_poll_ns_grow_start:uint
</span></span><span class="line"><span class="cl">parm:           halt_poll_ns_shrink:uint
</span></span></code></pre></div><p>其中<code>vermagic</code>就是<code>version magic</code>版本信息，可以看到当前<code>kvm.ko</code>的<code>version magic</code>版本信息为<code>6.4.0</code>。与前文的<code>uname -r</code>输出的 kernel 发行版本号<code>6.4.0-10.1.0.20.oe2309.riscv64</code>不一致。所以会报错。</p>
<h3 id="修改内核模块版本信息">修改内核模块版本信息</h3>
<ol>
<li>修改基础版本信息</li>
</ol>
<p>打开内核源代码根目录下的 Makefile 文件。你会找到一个包含内核版本信息的地方，类似于：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Makefile" data-lang="Makefile"><span class="line"><span class="cl"><span class="c"># SPDX-License-Identifier: GPL-2.0
</span></span></span><span class="line"><span class="cl"><span class="nv">VERSION</span> <span class="o">=</span> <span class="m">6</span>
</span></span><span class="line"><span class="cl"><span class="nv">PATCHLEVEL</span> <span class="o">=</span> <span class="m">4</span>
</span></span><span class="line"><span class="cl"><span class="nv">SUBLEVEL</span> <span class="o">=</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="nv">EXTRAVERSION</span> <span class="o">=</span>
</span></span></code></pre></div><p>表示内核版基础本号为<code>6.4.0</code>。</p>
<ol start="2">
<li>修改拓展版本信息</li>
</ol>
<p>kernel 引入了一些配置来增强版本信息，在内核源码的<code>&quot;include/linux/vermagic.h&quot;</code>下我们可以看到模块的健全版本信息，如下默认配置的有：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cm">/* Simply sanity version stamp for modules. */</span>
</span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_SMP
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_SMP &#34;SMP &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_SMP &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_PREEMPT_BUILD
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_PREEMPT &#34;preempt &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#elif defined(CONFIG_PREEMPT_RT)
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_PREEMPT &#34;preempt_rt &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_PREEMPT &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_MODULE_UNLOAD
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_MODULE_UNLOAD &#34;mod_unload &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_MODULE_UNLOAD &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp">#ifdef CONFIG_MODVERSIONS
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_MODVERSIONS &#34;modversions &#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_VERMAGIC_MODVERSIONS &#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl"><span class="cp">#ifdef RANDSTRUCT
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;generated/randstruct_hash.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_RANDSTRUCT &#34;RANDSTRUCT_&#34; RANDSTRUCT_HASHED_SEED
</span></span></span><span class="line"><span class="cl"><span class="cp">#else
</span></span></span><span class="line"><span class="cl"><span class="cp">#define MODULE_RANDSTRUCT
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#define VERMAGIC_STRING                                                 \
</span></span></span><span class="line"><span class="cl"><span class="cp">        UTS_RELEASE &#34; &#34;                                                 \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                     \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS       \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MODULE_ARCH_VERMAGIC                                            \
</span></span></span><span class="line"><span class="cl"><span class="cp">        MODULE_RANDSTRUCT
</span></span></span></code></pre></div><p>其中，<code>&quot;UTS_RELEASE&quot;</code>的配置在内核源码的<code>&quot;include/generated/utsrelease.h&quot;</code>下可以看到，<code>utsrelease.h</code>的内容是由<code>Makefile</code>和``.config<code>的内容来生成的，当成功编译kernel以后，</code>utsrelease.h`得到更新，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1">#defineUTS_RELEASE &#34;6.4.0&#34;</span>
</span></span></code></pre></div><p>那么前文&quot;6.4.0-d46299ae&quot;中的&quot;-d46299ae&quot;是如何得来的呢？其实这个是开发者使用了 Git 来管理代码。当你修改或者提交代码以后，每次编译内核后，在&quot;UTS_RELEASE&quot;后面就会看到一串哈希值，例如&quot;6.4.0-d46299ae&quot;，其中&quot;-d46299ae&quot;这个就是 Git 版本控制而产生的哈希值。发行版本号只是各个厂商用于区别自己发布的不同时期的 kernel 版本或者产品版本而产生的编号，完全由各厂商自己定义。</p>
<h2 id="解决-crc-校验错误">解决 CRC 校验错误</h2>
<p>我们可以通过一些手段修改新模块的 module_layout 的 CRC 与内核CRC相同，再插入。<code>/boot</code>目录下通常有个在<code>symvers-&lt;kernel_version&gt;.gz</code> 文件通常包含了内核模块的符号版本信息。这个文件是由 Linux 内核构建时生成的，用于记录在该内核版本下构建的模块的符号信息，包括函数和变量的名称、版本号等。里面就保存了内核的 module_layout 的 CRC 值。我们可以使用<code>gzip -d</code>命令解压这个文件，找到 module_layout 的 CRC 值，记录下来。</p>
<ul>
<li>
<p>方法一：使用 16 进制编辑器修改模块文件，将 module_layout 的值修改为相同的值，再插入。
在 Linux 中，可以使用 <code>hexdump</code> 和 <code>xxd</code> 等工具查看二进制文件的内容，并尝试编辑。下面是一种使用 <code>xxd</code> 查看和修改二进制文件的方法：</p>
<ol>
<li>
<p>使用 <code>xxd</code> 将二进制文件转换为十六进制文本：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">xxd /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko &gt; kvm_hex.txt
</span></span></code></pre></div><p>这将创建一个名为 <code>kvm_hex.txt</code> 的文本文件，其中包含 <code>kvm.ko</code> 的十六进制表示。</p>
</li>
<li>
<p>使用文本编辑器（如 <code>nano</code> 或 <code>vim</code>）打开 <code>kvm_hex.txt</code>，找到并编辑 <code>module_layout</code> 的值。请确保你了解所做更改的含义，并且只修改你确信的内容。</p>
</li>
<li>
<p>保存并关闭文本编辑器。</p>
</li>
<li>
<p>使用 <code>xxd</code> 将修改后的十六进制文本转换回二进制文件：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">xxd -r kvm_hex.txt &gt; /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko
</span></span></code></pre></div><p>这将覆盖原始的 <code>kvm.ko</code> 文件。</p>
</li>
</ol>
</li>
<li>
<p>方法二：修改 Module.symvers</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 清理编译结果。不要使用 make distclean，这会删除.config 文件以及 Module.symvers 文件</span>
</span></span><span class="line"><span class="cl">make clean
</span></span><span class="line"><span class="cl"><span class="c1"># 修改 Module.symvers 文件</span>
</span></span><span class="line"><span class="cl">sed -i  <span class="s1">&#39;/module_layout/ s/0x[0-9a-f][0-9a-f]*/0xdf88831e/&#39;</span> Module.symvers
</span></span><span class="line"><span class="cl"><span class="c1"># 重新编译模块</span>
</span></span><span class="line"><span class="cl">make <span class="nv">M</span><span class="o">=</span>./arch/riscv/kvm/ -j33
</span></span><span class="line"><span class="cl"><span class="c1"># 检查模块的 module_layout</span>
</span></span><span class="line"><span class="cl">modprobe --dump-modversions /usr/src/linux-6.4.0-10.1.0.20.oe2309.riscv64/arch/riscv/kvm/kvm.ko <span class="p">|</span> grep module_layout
</span></span><span class="line"><span class="cl">0xdf88831e
</span></span></code></pre></div></li>
</ul>
<h1 id="如何生成-modc-文件">如何生成 .mod.c 文件</h1>
<p>如果是自己写的模块，可以根据下面的命令编译模块，就可以得到<code>.mod.c</code>文件，它是源文件到<code>.mod.o</code>文件的一个中间文件。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make -C /root/build-kernel/kernel <span class="nv">M</span><span class="o">=</span>/driver_study/ modules -j22
</span></span></code></pre></div><p>如果是用内核自己的模块，执行<code>make modules</code>命令，也可以得到<code>.mod.c</code>文件。但是一般执行<code>make -j22</code>命令就不会生成这些文件，我们可以找一个启用的内核模块，例如<code>kvm.ko</code>，执行下面的命令，就可以得到<code>.mod.c</code>文件。不能随便找个模块，必须在 config 中开启的模块，否则会报错<code>undefined!</code>。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make  <span class="nv">M</span><span class="o">=</span>./arch/riscv/kvm modules -j22
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>构建和测试 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>
  </channel>
</rss>
