<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>even629</title>
  <icon>https://even629.com/en/icon.png</icon>
  <subtitle>blog</subtitle>
  <link href="https://even629.com/en/atom.xml" rel="self"/>
  
  <link href="https://even629.com/en/"/>
  <updated>2026-07-11T16:00:00.000Z</updated>
  <id>https://even629.com/en/</id>
  
  <author>
    <name>even629</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Tag Plugin Plus External Tags Overview</title>
    <link href="https://even629.com/en/posts/50013/"/>
    <id>https://even629.com/en/posts/50013/</id>
    <published>2026-07-11T12:00:00.000Z</published>
    <updated>2026-07-11T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-07-11</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the rendering support test of the current theme for standard Markdown and extended syntax, and provides a detailed overview of the Tag Plugin Plus external tags ported from the Butterfly theme to the Cactus theme, including the syntax and rendering effects of components such as link cards, inline text tags, prompts, collapsible boxes, timelines, and tab pages.</blockquote><hr><h1 id="Markdown-Basic-Syntax">Markdown Basic Syntax</h1><blockquote><p>The following tests the current theme’s rendering support for standard Markdown and extended syntax.</p></blockquote><hr><h2 id="Heading-Levels">Heading Levels</h2><h1 id="h1-Level-1-Heading">h1 Level 1 Heading</h1><h2 id="h2-Level-2-Heading">h2 Level 2 Heading</h2><h3 id="h3-Level-3-Heading">h3 Level 3 Heading</h3><h4 id="h4-Level-4-Heading">h4 Level 4 Heading</h4><h5 id="h5-Level-5-Heading">h5 Level 5 Heading</h5><h6 id="h6-Level-6-Heading">h6 Level 6 Heading</h6><hr><h2 id="Inline-Formatting">Inline Formatting</h2><p><strong>Bold Text</strong>、<em>Italic text</em>、<em><strong>Bold italic text</strong></em>、<s>Strikethrough text</s>、<code>Inline code</code></p><p><mark>Highlighted text</mark> (if supported), superscript X<sup>2</sup>, subscript H<sub>2</sub>O (if renderer supports)</p><h3 id="Highlight-mark-boundary">Highlight (mark) boundary</h3><p>Continuous highlight: <mark>first paragraph</mark> and <mark>second paragraph</mark> mixed with normal text.</p><p>Highlight nested format: <mark><strong>Bold</strong> + <code>Code</code> + <s>Delete</s></mark> Mixed inline syntax.</p><blockquote><p>Highlighted text inside a blockquote.</p></blockquote><div class="table-wrap"><table><thead><tr><th>Scene</th><th>Example</th></tr></thead><tbody><tr><td>Highlight in table</td><td><mark>Cell highlight</mark></td></tr><tr><td>Highlight with link</td><td><mark><a href="https://even629.com">even629</a></mark></td></tr></tbody></table></div><hr><h2 id="Link">Link</h2><h3 id="Normal-link">Normal link</h3><p><a href="https://even629.com">External link</a></p><h3 id="Link-with-title">Link with title</h3><p><a href="https://even629.com" title="even629的个人博客">even629’s blog</a></p><h3 id="Reference-link">Reference link</h3><p><a href="https://hexo.io" title="Hexo blogging framework">Hexo official site</a> and <a href="https://github.com/probberechts/hexo-theme-cactus" title="Cactus theme">Cactus theme</a></p><h3 id="Automatic-link">Automatic link</h3><p><a href="https://even629.com">https://even629.com</a></p><hr><h2 id="Image">Image</h2><h3 id="Normal-image">Normal image</h3><p><figure class="image-caption"><img loading="lazy" src="https://even629.com/images/linux_cover.webp" alt="Avatar"><figcaption>Avatar</figcaption></figure></p><h3 id="Image-with-title">Image with title</h3><p><figure class="image-caption"><img loading="lazy" src="https://even629.com/images/linux_cover.webp" alt="Avatar"><figcaption>Avatar</figcaption></figure></p><hr><h2 id="List">List</h2><h3 id="Unordered-list">Unordered list</h3><ul><li>First-level list item A</li><li>First-level list item B<ul><li>Second-level nested item B1</li><li>Second-level nested item B2<ul><li>Third-level nested item</li></ul></li></ul></li><li>First-level list item C</li></ul><h3 id="Ordered-list">Ordered list</h3><ol><li>Step 1</li><li>Step 2<ol><li>Sub-step A of Step 2</li><li>Sub-step B of Step 2</li></ol></li><li>Step 3</li></ol><h3 id="Task-list">Task list</h3><ul class="contains-task-list"><li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"> Completed tasks</li><li class="task-list-item"><input class="task-list-item-checkbox" disabled="" type="checkbox"> Uncompleted tasks</li><li class="task-list-item"><input class="task-list-item-checkbox" disabled="" type="checkbox"> To-do items<ul class="contains-task-list"><li class="task-list-item"><input class="task-list-item-checkbox" disabled="" type="checkbox"> Nested task items</li></ul></li></ul><h3 id="Task-list-boundary">Task list boundary</h3><ul class="contains-task-list"><li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"> Read <a href="https://hexo.io">Hexo documentation</a> and <strong>take notes</strong></li><li class="task-list-item"><input class="task-list-item-checkbox" disabled="" type="checkbox"> Run <code>hexo s</code> Local preview</li><li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"> Commit <s>Draft</s> Official version</li><li>Normal list item (mixed with task items)<ul class="contains-task-list"><li class="task-list-item"><input class="task-list-item-checkbox" disabled="" type="checkbox"> Nested task, containing <code>Inline code</code></li><li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"> Nested task completed</li></ul></li></ul><hr><h2 id="Quote">Quote</h2><h3 id="Single-level-quote">Single-level quote</h3><blockquote><p>This is a quote text.<br>Can span multiple lines.</p></blockquote><h3 id="Nested-quote">Nested quote</h3><blockquote><p>First-level quote</p><blockquote><p>Second-level quote</p><blockquote><p>Third-level quote</p></blockquote></blockquote></blockquote><h3 id="Quote-embedded-with-other-elements">Quote embedded with other elements</h3><blockquote><h2 id="Heading-inside-a-quote">Heading inside a quote</h2><ul><li>List item 1</li><li>List item 2</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;hello&quot;</span>)</span><br></pre></td></tr></table></figure><blockquote><p>Continue nesting</p></blockquote></blockquote><hr><h2 id="Code">Code</h2><h3 id="Inline-code">Inline code</h3><p>Used in text <code>print()</code> function to output content.</p><h3 id="Fenced-code-block">Fenced code block</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Hello, World!\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Specify-language-in-code-block">Specify language in code block</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">fibonacci</span>(<span class="params">n</span>):</span><br><span class="line">    a, b = <span class="number">0</span>, <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(n):</span><br><span class="line">        <span class="keyword">yield</span> a</span><br><span class="line">        a, b = b, a + b</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">list</span>(fibonacci(<span class="number">10</span>)))</span><br></pre></td></tr></table></figure><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">fn</span> <span class="title function_">main</span>() &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="variable">msg</span> = <span class="string">&quot;Hello, 世界!&quot;</span>;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;&#123;&#125;&quot;</span>, msg);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Escaping-in-code-block">Escaping in code block</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span>Hello <span class="symbol">&amp;amp;</span> welcome<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><hr><h2 id="Table">Table</h2><h3 id="Basic-table">Basic table</h3><div class="table-wrap"><table><thead><tr><th>Column A</th><th>Column B</th><th>Column C</th></tr></thead><tbody><tr><td>Value 1</td><td>Value 2</td><td>Value 3</td></tr><tr><td>Value 4</td><td>Value 5</td><td>Value 6</td></tr></tbody></table></div><h3 id="Align-Table">Align Table</h3><div class="table-wrap"><table><thead><tr><th style="text-align:left">Align Left</th><th style="text-align:center">Center Align</th><th style="text-align:right">Align Right</th></tr></thead><tbody><tr><td style="text-align:left">Left</td><td style="text-align:center">Center</td><td style="text-align:right">Right</td></tr><tr><td style="text-align:left">Cell</td><td style="text-align:center">Cell</td><td style="text-align:right">Cell</td></tr></tbody></table></div><h3 id="Inline-formatting-in-tables">Inline formatting in tables</h3><div class="table-wrap"><table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td><strong>Bold</strong></td><td><strong>Bold text</strong></td></tr><tr><td><code>Code</code></td><td><code>Inline code</code></td></tr><tr><td>Link</td><td><a href="https://even629.com">Click me</a></td></tr><tr><td>Mixed</td><td><strong>Bold</strong> + <code>Code</code> + <s>Strikethrough</s></td></tr></tbody></table></div><hr><h2 id="Horizontal-rule">Horizontal rule</h2><hr><hr><hr><hr><h2 id="Footnote">Footnote</h2><p>This is a text with a footnote<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>, and here is another footnote<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>.</p><hr><h2 id="Emoji">Emoji</h2><p>😆 🚀 ❤️ 👍 💯 🔥 💪 👏</p><hr><h2 id="escape-characters">escape characters</h2><p>*won’t become italic*  `won’t become code`  ~won’t become strikethrough~</p><hr><h2 id="Mathematical-formulas-KaTeX">Mathematical formulas (KaTeX)</h2><h3 id="Inline-formula">Inline formula</h3><p>Mass-energy equivalence:<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>E</mi><mo>=</mo><mi>m</mi><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">E = mc^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8141em;"></span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal">c</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></p><p>Euler’s formula:<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>e</mi><mrow><mi>i</mi><mi>π</mi></mrow></msup><mo>+</mo><mn>1</mn><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">e^{i\pi} + 1 = 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.908em;vertical-align:-0.0833em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8247em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">iπ</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span></p><h3 id="Block-level-formula">Block-level formula</h3><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><msub><mi>x</mi><mi>i</mi></msub><mo>=</mo><msub><mi>x</mi><mn>1</mn></msub><mo>+</mo><msub><mi>x</mi><mn>2</mn></msub><mo>+</mo><mo>⋯</mo><mo>+</mo><msub><mi>x</mi><mi>n</mi></msub></mrow><annotation encoding="application/x-tex">\sum_{i=1}^{n} x_i = x_1 + x_2 + \cdots + x_n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.9291em;vertical-align:-1.2777em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6514em;"><span style="top:-1.8723em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.05em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2777em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.5806em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span></p><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msubsup><mo>∫</mo><mi>a</mi><mi>b</mi></msubsup><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mtext> </mtext><mi>d</mi><mi>x</mi><mo>=</mo><mi>F</mi><mo stretchy="false">(</mo><mi>b</mi><mo stretchy="false">)</mo><mo>−</mo><mi>F</mi><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\int_{a}^{b} f(x)\,dx = F(b) - F(a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.511em;vertical-align:-0.9119em;"></span><span class="mop"><span class="mop op-symbol large-op" style="margin-right:0.44445em;position:relative;top:-0.0011em;">∫</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.599em;"><span style="top:-1.7881em;margin-left:-0.4445em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span style="top:-3.8129em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9119em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mopen">(</span><span class="mord mathnormal">b</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span></span></span></p><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mo fence="true">[</mo><mtable rowspacing="0.16em" columnalign="center center center" columnspacing="1em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>1</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>2</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>3</mn></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>4</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>5</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>6</mn></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>7</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>8</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mn>9</mn></mstyle></mtd></mtr></mtable><mo fence="true">]</mo></mrow><annotation encoding="application/x-tex">\begin{bmatrix}1 &amp; 2 &amp; 3 \\4 &amp; 5 &amp; 6 \\7 &amp; 8 &amp; 9\end{bmatrix}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:3.6em;vertical-align:-1.55em;"></span><span class="minner"><span class="mopen"><span class="delimsizing mult"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.05em;"><span class="pstrut" style="height:5.6em;"></span><span style="width:0.667em;height:3.600em;"><svg xmlns="http://www.w3.org/2000/svg" width="0.667em" height="3.600em" viewBox="0 0 667 3600"><path d="M403 1759 V84 H666 V0 H319 V1759 v0 v1759 h347 v-84H403z M403 1759 V0 H319 V1759 v0 v1759 h84z"/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.55em;"><span></span></span></span></span></span></span><span class="mord"><span class="mtable"><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span><span style="top:-3.01em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">4</span></span></span><span style="top:-1.81em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">7</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.55em;"><span></span></span></span></span></span><span class="arraycolsep" style="width:0.5em;"></span><span class="arraycolsep" style="width:0.5em;"></span><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.01em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">5</span></span></span><span style="top:-1.81em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">8</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.55em;"><span></span></span></span></span></span><span class="arraycolsep" style="width:0.5em;"></span><span class="arraycolsep" style="width:0.5em;"></span><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">3</span></span></span><span style="top:-3.01em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">6</span></span></span><span style="top:-1.81em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">9</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.55em;"><span></span></span></span></span></span></span></span><span class="mclose"><span class="delimsizing mult"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.05em;"><span class="pstrut" style="height:5.6em;"></span><span style="width:0.667em;height:3.600em;"><svg xmlns="http://www.w3.org/2000/svg" width="0.667em" height="3.600em" viewBox="0 0 667 3600"><path d="M347 1759 V0 H0 V84 H263 V1759 v0 v1759 H0 v84 H347zM347 1759 V0 H263 V1759 v0 v1759 h84z"/></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.55em;"><span></span></span></span></span></span></span></span></span></span></span></span></p><hr><hr><h1 id="Tag-Plugin-Plus-External-Tags">Tag Plugin Plus External Tags</h1><blockquote><p>The following shows all plug-in tags and their variants ported from Butterfly to Cactus.</p></blockquote><hr><h2 id="Link-Card-link">Link Card (link)</h2><h3 id="Link-with-image">Link with image</h3><div class="tag link"><a class="link-card" title="even629's blog" href="https://even629.com"><div class="left"><img loading="lazy" src="https://even629.com/images/linux_cover.webp"/></div><div class="right"><p class="text">even629's blog</p><p class="url">https://even629.com</p></div></a></div><h3 id="Link-without-image">Link without image</h3><div class="tag link"><a class="link-card" title="HexoOfficial website" href="https://hexo.io"><div class="left"><img loading="lazy" src="/images/logo.webp"/></div><div class="right"><p class="text">HexoOfficial website</p><p class="url">https://hexo.io</p></div></a></div><blockquote><p>Syntax:<code>&#123;% link Title, Link, ImageURL(Optional) %&#125;</code></p></blockquote><hr><h2 id="Link-card">Link card</h2><div class="tag link"><a class="link-card" title="Hexo" href="https://hexo.io"><div class="left"><img loading="lazy" src="https://hexo.io/icon/favicon-196x196.png"/></div><div class="right"><p class="text">Hexo</p><p class="url">https://hexo.io</p></div></a></div><div class="tag link"><a class="link-card" title="Cactus" href="https://github.com/probberechts/hexo-theme-cactus"><div class="left"><img loading="lazy" src="/images/logo.webp"/></div><div class="right"><p class="text">Cactus</p><p class="url">https://github.com/probberechts/hexo-theme-cactus</p></div></a></div><div class="tag link"><a class="link-card" title="Font Awesome" href="https://fontawesome.com"><div class="left"><img loading="lazy" src="/images/logo.webp"/></div><div class="right"><p class="text">Font Awesome</p><p class="url">https://fontawesome.com</p></div></a></div><blockquote><p>Syntax:<code>&#123;% link ... %&#125;</code></p></blockquote><hr><h2 id="Inline-image-inlineimage">Inline image (inlineimage)</h2><p>Within a paragraph <img class="inline-img" no-lazy src="https://even629.com/images/linux_cover.webp"  /> Embed inline icon.</p><p>Custom height:<img class="inline-img" no-lazy src="https://even629.com/images/linux_cover.webp" style="height:2em" /></p><blockquote><p>Syntax:<code>&#123;% inlineimage ImageURL, height=Height(Optional) %&#125;</code></p></blockquote><hr><h2 id="Inline-text-label">Inline text label</h2><h3 id="Style-overview">Style overview</h3><div class="table-wrap"><table><thead><tr><th>Tag</th><th>Effect</th><th>Description</th></tr></thead><tbody><tr><td>u</td><td><u>Underlined text</u></td><td>Underline</td></tr><tr><td>emp</td><td><emp>Emphasized text</emp></td><td>Emphasis mark</td></tr><tr><td>wavy</td><td><wavy>wavy line text</wavy></td><td>wavy underline</td></tr><tr><td>kbd</td><td><kbd>Ctrl</kbd> + <kbd>C</kbd></td><td>keyboard key</td></tr><tr><td>psw</td><td><psw>password text</psw></td><td>password obscured (visible on hover)</td></tr><tr><td>del</td><td><del>deleted text</del></td><td>strikethrough</td></tr></tbody></table></div><h3 id="combined-use">combined use</h3><p>press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> Open developer tools.</p><p>This is a paragraph containing<u>underline</u>、<emp>emphasis</emp>and<wavy>wavy line</wavy>mixed text.</p><blockquote><p>Syntax:<code>&#123;% Tag name Text content %&#125;</code> — No closing tag</p></blockquote><hr><h2 id="Colored-paragraph-p-and-inline-span">Colored paragraph (p) and inline (span)</h2><h3 id="Color-test">Color test</h3><p class='p Red'>Red paragraph text</p><p class='p Blue'>Blue paragraph text</p><p class='p Green'>Green paragraph</p><p class='p Yellow'>Yellow paragraph</p><p class='p cyan'>cyan paragraph</p><p class='p purple'>purple paragraph</p><p class='p gray'>gray paragraph</p><h3 id="inline-span">inline span</h3><p>This is a piece of text, which contains<span class='p red'>red text</span>and<span class='p blue'>blue text</span>。</p><h3 id="alignment">alignment</h3><p class='p center'>centered paragraph text</p><p class='p right'>Right-aligned paragraph text</p><h3 id="Font-size">Font size</h3><p class='p large'>Large font paragraph</p><p class='p huge'>Extra large font paragraph</p><blockquote><p>Syntax:<code>&#123;% p Color, Text %&#125;</code> / <code>&#123;% span Color, Text %&#125;</code> — Colors support Chinese and English (red/red, blue/blue, etc.)</p></blockquote><hr><h2 id="Tip-box-tip">Tip box (tip)</h2><h3 id="Basic-style">Basic style</h3><div class="tip info"><p>Default style tip box</p></div><div class="tip info"><p>Info style tip</p></div><div class="tip success"><p>Success style tip (success tip)</p></div><div class="tip warning"><p>tip with warning style (warning prompt)</p></div><div class="tip danger"><p>tip with danger style (danger prompt)</p></div><h3 id="extended-styles">extended styles</h3><div class="tip bolt"><p>bolt style (lightning icon)</p></div><div class="tip ban"><p>ban style (prohibition icon)</p></div><div class="tip home"><p>home style (home icon)</p></div><div class="tip sync"><p>sync style (sync icon)</p></div><div class="tip cogs"><p>cogs style (gear icon)</p></div><div class="tip key"><p>key style (key icon)</p></div><div class="tip bell"><p>bell style (bell icon)</p></div><blockquote><p>Syntax:<code>&#123;% tip Style name %&#125; Content &#123;% endtip %&#125;</code> — Styles: info / success / warning / danger / bolt / ban / home / sync / cogs / key / bell</p></blockquote><hr><h2 id="Folding-container-folding">Folding container (folding)</h2><h3 id="Default-style">Default style</h3><details class="folding-tag" ><summary> Click to expand for details </summary>            <div class='content'>            <p>Content in the collapsible box, supports <strong>Markdown</strong> syntax.</p><ul><li>List item</li><li><code>Inline code</code></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;折叠框内的代码&quot;</span>);</span><br></pre></td></tr></table></figure>            </div>          </details><h3 id="Color-variant">Color variant</h3><details class="folding-tag" blue><summary> Blue collapsible </summary>            <div class='content'>            <p>Collapsible box with blue border</p>            </div>          </details><details class="folding-tag" red><summary> Red collapsible </summary>            <div class='content'>            <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;红色折叠内的代码块\n&quot;</span>);</span><br></pre></td></tr></table></figure>            </div>          </details><details class="folding-tag" green><summary> Green collapsible </summary>            <div class='content'>            <p>Green collapsible box content</p>            </div>          </details><details class="folding-tag" purple><summary> Purple collapsible </summary>            <div class='content'>            <p>Purple collapsible box content</p>            </div>          </details><details class="folding-tag" cyan><summary> Cyan collapsible </summary>            <div class='content'>            <p>Cyan collapsible box content</p>            </div>          </details><details class="folding-tag" yellow><summary> Yellow collapsible </summary>            <div class='content'>            <p>Yellow collapsible box content</p>            </div>          </details><details class="folding-tag" orange><summary> Orange collapsible </summary>            <div class='content'>            <p>Orange collapsible box content</p>            </div>          </details><h3 id="Collapsible-box-expanded-by-default">Collapsible box expanded by default</h3><details class="folding-tag" green open><summary> Green collapsible box expanded by default </summary>            <div class='content'>            <p>This collapsible box is expanded by default (add <code>open</code> key word).</p>            </div>          </details><h3 id="Table-embedded-in-collapsible-box">Table embedded in collapsible box</h3><details class="folding-tag" blue><summary> Table inside collapsible box </summary>            <div class='content'>            <div class="table-wrap"><table><thead><tr><th>Name</th><th>Value</th></tr></thead><tbody><tr><td>Attribute A</td><td>100</td></tr><tr><td>Attribute B</td><td>200</td></tr></tbody></table></div>            </div>          </details><h3 id="Collapsible-box-nesting">Collapsible box nesting</h3><details class="folding-tag" green><summary> Outer collapsible </summary>            <div class='content'>            <p>Outer content</p><details class="folding-tag" orange><summary> Inner collapsible </summary>            <div class='content'>            <p>Inner content</p>            </div>          </details>            </div>          </details><blockquote><p>Syntax:<code>&#123;% folding [Color] [open], Title %&#125; Content &#123;% endfolding %&#125;</code> — Color (optional): blue / red / green / purple / cyan / yellow / orange; add <code>open</code> Keyword makes the collapsible box expanded by default</p></blockquote><hr><h2 id="Timeline-timeline">Timeline (timeline)</h2><h3 id="Blue-timeline">Blue timeline</h3><div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>My timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2024年</p></div></div><div class='timeline-item-content'><p>Started a blog and built a Hexo site.</p></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2025年</p></div></div><div class='timeline-item-content'><p>Migrate to Cactus theme to optimize reading experience.</p></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026年</p></div></div><div class='timeline-item-content'><p>Improve plugin tags and add English translations.</p></div></div></div><h3 id="Green-timeline">Green timeline</h3><div class="timeline green"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Project progress</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>Q1</p></div></div><div class='timeline-item-content'><p>Requirements analysis and design</p></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>Q2</p></div></div><div class='timeline-item-content'><p>Core feature development</p></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>Q3</p></div></div><div class='timeline-item-content'><p>Testing and deployment launch</p></div></div></div><h3 id="Other-color-variants">Other color variants</h3><div class="timeline red"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Red timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>节点一</p></div></div><div class='timeline-item-content'><p>Red timeline node content</p></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>节点二</p></div></div><div class='timeline-item-content'><p>Contains <strong>Bold</strong> and <code>code</code> node</p></div></div></div><div class="timeline orange"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Orange timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>橙色节点</p></div></div><div class='timeline-item-content'><p>Orange timeline node content</p></div></div></div><div class="timeline purple"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Purple timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>紫色节点</p></div></div><div class='timeline-item-content'><p>Purple timeline node content</p></div></div></div><blockquote><p>Syntax:<code>&#123;% timeline Title, Color %&#125; <!-- timeline 节点名 --> Content <!-- endtimeline --> &#123;% endtimeline %&#125;</code> — Color: blue / green / red / orange / purple</p></blockquote><hr><h2 id="Tabs">Tabs</h2><h3 id="Basic-tabs">Basic tabs</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">C</button><button type="button" class="tab">Rust</button><button type="button" class="tab">Python</button></div><div class="tab-contents"><div class="tab-item-content active"><p>C is a general-purpose procedural programming language.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;hello\n&quot;</span>);</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><p>Rust is a systems programming language focused on safety.</p><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">println!</span>(<span class="string">&quot;hello&quot;</span>);</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><p>Python is a concise and elegant interpreted language.</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(<span class="string">&quot;hello&quot;</span>)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="Specify-the-default-active-tab">Specify the default active tab</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab">标签一</button><button type="button" class="tab">标签二</button><button type="button" class="tab active">标签三（默认激活）</button></div><div class="tab-contents"><div class="tab-item-content"><p>Content of the first tab</p></div><div class="tab-item-content"><p>Content of the second tab</p></div><div class="tab-item-content active"><p>Content of the third tab, automatically displayed when the page loads.</p></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="Tabs-with-icons">Tabs with icons</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active"><i class="fa-solid fa-code"></i></button><button type="button" class="tab"><i class="fa-solid fa-paint-brush"></i></button></div><div class="tab-contents"><div class="tab-item-content active"><p>Code-related content</p></div><div class="tab-item-content"><p>Design-related content</p></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><blockquote><p>Syntax:<code>&#123;% tabs Title, Default active index %&#125; <!-- tab 标签名 --> Content <!-- endtab --> &#123;% endtabs %&#125;</code> — With icons:<code>&lt;!-- tab @fa-icon-class --&gt;</code></p></blockquote><hr><h2 id="Multi-level-tabs-subtabs">Multi-level tabs (subtabs)</h2><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">一级 A</button><button type="button" class="tab">一级 B</button></div><div class="tab-contents"><div class="tab-item-content active"><p>This is the content of the first-level tab A.</p><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">子 1</button><button type="button" class="tab">子 2</button></div><div class="tab-contents"><div class="tab-item-content active"><p>Content of sub-tab 1</p></div><div class="tab-item-content"><p>Content of sub-tab 2</p></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div></div><div class="tab-item-content"><p>Content of the first-level tab B.</p></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><blockquote><p>Syntax: In <code>tab</code> inner nesting <code>subtabs</code> / <code>subsubtabs</code>(same syntax as <code>tabs</code>）</p></blockquote><hr><h2 id="Annotation-box-note">Annotation box (note)</h2><h3 id="Four-basic-styles">Four basic styles</h3><div class="note flat"><p>Flat style note (default), suitable for general reminders.</p></div><div class="note modern"><p>Modern style note, clean solid background.</p></div><div class="note simple"><p>Simple style note, with a colored border on the left.</p></div><div class="note disabled"><p>Disabled style note, gray tones.</p></div><h3 id="Note-with-title">Note with title</h3><div class="note flat"><div class="note-title">Precautions</div><p>Please read the documentation carefully before use.</p></div><h3 id="Note-with-icon">Note with icon</h3><div class="note flat icon-padding"><i class="note-icon fa-solid fa-lightbulb"></i><div class="note-title">Tip</div><p>Note with light bulb icon as a reminder.</p></div><div class="note flat icon-padding"><i class="note-icon fa-solid fa-triangle-exclamation"></i><div class="note-title">Warning</div><p>Note with warning icon.</p></div><h3 id="Note-with-embedded-Markdown">Note with embedded Markdown</h3><div class="note modern"><p>Supports <strong>bold</strong>、<em>italic</em>、<code>code</code> and other inline formats.</p><ul><li>List item</li><li>Can also have code blocks</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> msg = <span class="string">&quot;hello&quot;</span>;</span><br></pre></td></tr></table></figure></div><h3 id="Title-Icon-Style-combination">Title + Icon + Style combination</h3><div class="note flat icon-padding"><i class="note-icon fa-solid fa-circle-info"></i><div class="note-title">modern Modern style with title</div><p>Modern note with title, icon, and style all present.</p></div><div class="note flat icon-padding"><i class="note-icon fa-solid fa-lightbulb"></i><div class="note-title">simple Simple style with title</div><p>Simple style + title + light bulb icon.</p></div><div class="note flat"><div class="note-title">disabled Disabled with title</div><p>Disabled style + title, no icon.</p></div><blockquote><p>Syntax:<code>&#123;% note Title(Optional), Icon(Optional) %&#125; Content &#123;% endnote %&#125;</code> — Style controlled via CSS class</p></blockquote><hr><h2 id="Progress-bar-progress">Progress bar (progress)</h2><h3 id="Basic-colors">Basic colors</h3><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-green"  style="width: 90%" aria-valuenow="90" aria-valuemin="0" aria-valuemax="100"><p>90% Completed</p></div></div><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-yellow"  style="width: 60%" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"><p>60% In Progress</p></div></div><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-red"  style="width: 30%" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100"><p>30% Blocked</p></div></div><h3 id="Extended-colors">Extended colors</h3><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-cyan"  style="width: 80%" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"><p>info Progress</p></div></div><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-blue"  style="width: 70%" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100"><p>primary Progress</p></div></div><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-blue"  style="width: 50%" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"><p>blue Progress</p></div></div><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-gray"  style="width: 40%" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"><p>gray Progress</p></div></div><h3 id="Boundary-values">Boundary values</h3><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-green"  style="width: 100%" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"><p>100% All Completed</p></div></div><div class="progress"><div class="progress-bar-animated progress-bar progress-bar-striped bg-cyan"  style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"><p>0% Not Started</p></div></div><blockquote><p>Syntax:<code>&#123;% progress Width percentage, Color, Label text %&#125;</code> — Color: success / warning / danger / info / primary / blue / gray</p></blockquote><hr><h2 id="Checkbox">Checkbox</h2><h3 id="Default-state">Default state</h3><div class='checkbox'><input type="checkbox" />            <p>Apple</p>            </div><div class='checkbox'><input type="checkbox" />            <p>Banana</p>            </div><div class='checkbox'><input type="checkbox" />            <p>Strawberry</p>            </div><h3 id="Selected-state">Selected state</h3><div class='checkbox'><input type="checkbox" checked="checked"/>            <p>Watermelon</p>            </div><div class='checkbox'><input type="checkbox" checked="checked"/>            <p>Grape</p>            </div><h3 id="Color-variants">Color variants</h3><div class='checkbox red red'><input type="checkbox" checked="checked"/>            <p>checkbox</p>            </div><div class='checkbox green green'><input type="checkbox" checked="checked"/>            <p>checkbox</p>            </div><div class='checkbox blue blue'><input type="checkbox" />            <p>checkbox</p>            </div><div class='checkbox yellow yellow'><input type="checkbox" />            <p>checkbox</p>            </div><div class='checkbox cyan cyan'><input type="checkbox" />            <p>checkbox</p>            </div><h3 id="style-variant">style variant</h3><div class='checkbox plus plus'><input type="checkbox" />            <p>sign style</p>            </div><div class='checkbox minus minus'><input type="checkbox" />            <p>sign style</p>            </div><div class='checkbox times'><input type="checkbox" />            <p>cross sign style</p>            </div><h3 id="radio-button">radio button</h3><div class='checkbox'><input type="radio" checked="checked"/>            <p>option one</p>            </div><div class='checkbox'><input type="radio" />            <p>option two</p>            </div><div class='checkbox red red'><input type="radio" />            <p>button</p>            </div><h3 id="color-and-style-overlay">color and style overlay</h3><div class='checkbox red plus red plus'><input type="checkbox" checked="checked"/>            <p>sign</p>            </div><div class='checkbox green minus green minus'><input type="checkbox" checked="checked"/>            <p>sign</p>            </div><div class='checkbox yellow times yellow'><input type="checkbox" />            <p>cross sign</p>            </div><div class='checkbox cyan cyan'><input type="radio" checked="checked"/>            <p>button</p>            </div><div class='checkbox blue plus blue plus'><input type="checkbox" />            <p>sign</p>            </div><blockquote><p>Syntax:<code>&#123;% checkbox Text, checked(Optional) %&#125;</code> — Color/style placed before text:<code>red</code> / <code>green</code> / <code>blue</code> / <code>yellow</code> / <code>cyan</code> / <code>plus</code> / <code>minus</code> / <code>times</code> / <code>radio</code></p></blockquote><hr><h2 id="Bubble-note-bubble">Bubble note (bubble)</h2><h3 id="Default-color">Default color</h3><p>Move the mouse to<span class="bubble-content">this word</span><span class="bubble-notation"><span class="bubble-item" style="background-color:#71a4e3;"> This is the annotation text</span></span>to view the annotation.</p><h3 id="Custom-color">Custom color</h3><span class="bubble-content">another word</span><span class="bubble-notation"><span class="bubble-item" style="background-color: #e91e63;"> another annotation</span></span><h3 id="Consecutive-bubbles">Consecutive bubbles</h3><p>A sentence can have<span class="bubble-content">multiple</span><span class="bubble-notation"><span class="bubble-item" style="background-color:#71a4e3;"> first comment</span></span><span class="bubble-content">bubble</span><span class="bubble-notation"><span class="bubble-item" style="background-color: #4caf50;"> second comment</span></span>arranged in order.</p><blockquote><p>Syntax:<code>&#123;% bubble text, comment, color(optional) %&#125;</code> — no closing tag, hover to show comment</p></blockquote><hr><h2 id="reference-tag-referto-referfrom">reference tag (referto + referfrom)</h2><h3 id="single-reference">single reference</h3><p>reference mark in text<span class="hidden-anchor" id="referto_1"></span><sup class="reference"><a href="#referfrom_1">1</a></sup><span class="reference-bubble"><span class="reference-item"><span class="reference-literature">HexoOfficial documentation</span></span></span>, click the number to jump to the references at the end of the document.</p><div class="reference-source"><span class="hidden-anchor" id="referfrom_1"></span><a class="reference-anchor" href="#referto_1">1<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Hexo Official documentation" href="https://hexo.io">Hexo Official documentation</a></div><h3 id="Multiple-references">Multiple references</h3><p>This is the 2nd reference<span class="hidden-anchor" id="referto_2"></span><sup class="reference"><a href="#referfrom_2">2</a></sup><span class="reference-bubble"><span class="reference-item"><span class="reference-literature">Cactus Theme GitHub</span></span></span>and the 3rd reference<span class="hidden-anchor" id="referto_3"></span><sup class="reference"><a href="#referfrom_3">3</a></sup><span class="reference-bubble"><span class="reference-item"><span class="reference-literature">Font Awesome Icon library</span></span></span>。</p><p>4th reference<span class="hidden-anchor" id="referto_4"></span><sup class="reference"><a href="#referfrom_4">4</a></sup><span class="reference-bubble"><span class="reference-item"><span class="reference-literature">Super extremely long title test</span></span></span></p><div class="reference-source"><span class="hidden-anchor" id="referfrom_2"></span><a class="reference-anchor" href="#referto_2">2<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Cactus Theme GitHub" href="https://github.com/probberechts/hexo-theme-cactus">Cactus Theme GitHub</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_3"></span><a class="reference-anchor" href="#referto_3">3<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Font Awesome Icon library" href="https://fontawesome.com">Font Awesome Icon library</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_4"></span><a class="reference-anchor" href="#referto_4">4<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Super extremely long title test" href="https://fontawesome.com">Super extremely long title test</a></div><blockquote><p>Syntax:<code>&#123;% referto 'Number','Reference title' %&#125;</code> In-text mark + <code>&#123;% referfrom 'Number','Reference title','URL' %&#125;</code> End-of-text list</p><p>Hovering the mouse over the number displays a preview of the reference title; clicking jumps to the corresponding entry at the end of the text.</p></blockquote><hr class="footnotes-sep"><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>Content of the first footnote. <a href="#fnref1" class="footnote-backref">↩︎</a></p></li><li id="fn2" class="footnote-item"><p>The second footnote can contain<strong>formatting</strong>and<code>code</code>。 <a href="#fnref2" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
    
    
    <summary type="html">This article introduces the rendering support test of the current theme for standard Markdown and extended syntax, and provides a detailed overview of the Tag Plugin Plus external tags ported from the Butterfly theme to the Cactus theme, including the syntax and rendering effects of components such as link cards, inline text tags, prompts, collapsible boxes, timelines, and tab pages.</summary>
    
    
    
    <category term="tools" scheme="https://even629.com/en/categories/tools/"/>
    
    
    <category term="hexo" scheme="https://even629.com/en/tags/hexo/"/>
    
  </entry>
  
  <entry>
    <title>Remoteproc resource table</title>
    <link href="https://even629.com/en/posts/202607041/"/>
    <id>https://even629.com/en/posts/202607041/</id>
    <published>2026-07-04T09:42:13.000Z</published>
    <updated>2026-07-04T09:42:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-07-04</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the structure and function of the resource table in the remote processor firmware image, detailing how the main processor, after loading the firmware, decodes the resource table to allocate system resources such as physical memory, configure Virtio devices, and create RPMsg channels for inter-core communication. Additionally, using the STM32MP15C reference code, it summarizes the specific definitions of resource entries under the Remoteproc framework and the implementation of dynamic resource management based on OpenAMP.</blockquote><hr><p>Reference code:</p><p>STM32CubeMP1 MPU Firmware Package</p><ul><li>STM32MP157C-EV1 RevC</li><li>STM32MP157C-DK2 RevC</li></ul><div class="tag link"><a class="link-card" title="STM32CubeMP1" href="https://github.com/STMicroelectronics/STM32CubeMP1/"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">STM32CubeMP1</p><p class="url">https://github.com/STMicroelectronics/STM32CubeMP1/</p></div></a></div> <h1 id="Remote-processor-firmware-image">Remote processor firmware image</h1><p>The firmware image of a remote processor generally includes:</p><ul><li>Resource table (resource_table)</li><li>User application</li><li>RTOS or bare metal (BM) related code</li><li>OpenAMP library.</li></ul><p>After the main processor loads the remote processor’s firmware into the remote processor’s core, it decodes the firmware image to obtain associated resources and reserves memory for the firmware code and data segments. Once the remote processor is started, the main processor creates an RPMsg channel, which is used for remote communication.</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/remoteproc/202607041/remoteproc-image-drawio.png" alt="remoteproc_image.drawio"><figcaption>remoteproc_image.drawio</figcaption></figure></p><p>The resources of the remote processor include:</p><ul><li>System resources required by the remote processor before power-up, such as contiguous physical memory allocated to the remote processor and peripherals assigned to it (these devices can be reserved or unused), are configured in the<code>stm32mp157-m4-srm.dtsi</code>resource manager of the device tree file (i.e., the<code>m4_system_resources</code>node).</li><li>In addition to system resources, each remote processor has a resource table (<code>resource_table</code>), and the resource table may also contain resource entries that publish the functions supported by the remote processor or existing configurations, such as the vring address and vring size in Virtio devices.</li></ul><p>Only after all resource requirements are met (M-core side configuration requirements, the resource table will require Linux to allocate corresponding resources, etc.), Remotecore will start the device.</p><h1 id="Resource-Table">Resource Table</h1><p>Under the kernel source code<code>include/linux/remoteproc.h</code>file, find the following structure resource_table, which is the firmware resource table header:</p><h2 id="struct-resource-table-defined-by-Linux">struct resource_table defined by Linux</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct resource_table - firmware resource table header</span></span><br><span class="line"><span class="comment"> * @ver: version number</span></span><br><span class="line"><span class="comment"> * @num: number of resource entries</span></span><br><span class="line"><span class="comment"> * @reserved: reserved (must be zero)</span></span><br><span class="line"><span class="comment"> * @offset: array of offsets pointing at the various resource entries</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * A resource table is essentially a list of system resources required</span></span><br><span class="line"><span class="comment"> * by the remote processor. It may also include configuration entries.</span></span><br><span class="line"><span class="comment"> * If needed, the remote processor firmware should contain this table</span></span><br><span class="line"><span class="comment"> * as a dedicated &quot;.resource_table&quot; ELF section.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Some resources entries are mere announcements, where the host is informed</span></span><br><span class="line"><span class="comment"> * of specific remoteproc configuration. Other entries require the host to</span></span><br><span class="line"><span class="comment"> * do something (e.g. allocate a system resource). Sometimes a negotiation</span></span><br><span class="line"><span class="comment"> * is expected, where the firmware requests a resource, and once allocated,</span></span><br><span class="line"><span class="comment"> * the host should provide back its details (e.g. address of an allocated</span></span><br><span class="line"><span class="comment"> * memory region).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * The header of the resource table, as expressed by this structure,</span></span><br><span class="line"><span class="comment"> * contains a version number (should we need to change this format in the</span></span><br><span class="line"><span class="comment"> * future), the number of available resource entries, and their offsets</span></span><br><span class="line"><span class="comment"> * in the table.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Immediately following this header are the resource entries themselves,</span></span><br><span class="line"><span class="comment"> * each of which begins with a resource entry header (as described below).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">resource_table</span> &#123;</span></span><br><span class="line">u32 ver;</span><br><span class="line">u32 num;</span><br><span class="line">u32 reserved[<span class="number">2</span>];</span><br><span class="line">u32 offset[];</span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><p>Following this firmware resource table header are the resource entries themselves. <strong>Each entry starts with a<code>struct fw_rsc_hdr</code>header</strong>, and the content of the entry itself follows this header, parsed according to the resource type. Below is the beginning of the resource entry header:</p><h3 id="struct-fw-rsc-hdr">struct fw_rsc_hdr</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_hdr - firmware resource entry header</span></span><br><span class="line"><span class="comment"> * @type: resource type</span></span><br><span class="line"><span class="comment"> * @data: resource data</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Every resource entry begins with a &#x27;struct fw_rsc_hdr&#x27; header providing</span></span><br><span class="line"><span class="comment"> * its @type. The content of the entry itself will immediately follow</span></span><br><span class="line"><span class="comment"> * this header, and it should be parsed according to the resource type.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_hdr</span> &#123;</span></span><br><span class="line">u32 type;</span><br><span class="line">u8 data[];</span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><p>The resource type is defined as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * enum fw_resource_type - types of resource entries</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @RSC_CARVEOUT:   request for allocation of a physically contiguous</span></span><br><span class="line"><span class="comment"> *    memory region.</span></span><br><span class="line"><span class="comment"> * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.</span></span><br><span class="line"><span class="comment"> * @RSC_TRACE:    announces the availability of a trace buffer into which</span></span><br><span class="line"><span class="comment"> *    the remote processor will be writing logs.</span></span><br><span class="line"><span class="comment"> * @RSC_VDEV:       declare support for a virtio device, and serve as its</span></span><br><span class="line"><span class="comment"> *    virtio header.</span></span><br><span class="line"><span class="comment"> * @RSC_LAST:       just keep this one at the end of standard resources</span></span><br><span class="line"><span class="comment"> * @RSC_VENDOR_START:start of the vendor specific resource types range</span></span><br><span class="line"><span class="comment"> * @RSC_VENDOR_END:end of the vendor specific resource types range</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * For more details regarding a specific resource type, please see its</span></span><br><span class="line"><span class="comment"> * dedicated structure below.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Please note that these values are used as indices to the rproc_handle_rsc</span></span><br><span class="line"><span class="comment"> * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to</span></span><br><span class="line"><span class="comment"> * check the validity of an index before the lookup table is accessed, so</span></span><br><span class="line"><span class="comment"> * please update it as needed.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">fw_resource_type</span> &#123;</span></span><br><span class="line">RSC_CARVEOUT= <span class="number">0</span>,</span><br><span class="line">RSC_DEVMEM= <span class="number">1</span>,</span><br><span class="line">RSC_TRACE= <span class="number">2</span>,</span><br><span class="line">RSC_VDEV= <span class="number">3</span>,</span><br><span class="line">RSC_LAST= <span class="number">4</span>,</span><br><span class="line">RSC_VENDOR_START= <span class="number">128</span>,</span><br><span class="line">RSC_VENDOR_END= <span class="number">512</span>,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>The above values are used as<code>rproc_handle_rsc()</code>indices for the lookup table of the function (in the<code>remoteproc_internal.h</code>file).</p><p>When registering a new remote processor, the Remoteproc framework will look up its resource table and register the Virtio devices it supports. The firmware should provide Remoteproc information about the Virtio devices it supports and their configurations,<code>RSC_VDEV</code>and the resource entry should specify the Virtio device ID (such as<code>virtio_ids.h</code>), Virtio functions, Virtio configuration space, vrings information, etc. We can obtain this by checking the Linux file system<code>/sys/kernel/debug/remoteproc/remoteproc0/resource_table</code>file to get the RSC_VDEV information. (That is, through the<code>rproc_handle_rsc()</code>function to first look up the relevant attributes, and then go to<code>RSC_VDEV</code>to find the specific configuration of that attribute.)</p><h4 id="struct-fw-rsc-carveout">struct fw_rsc_carveout</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_carveout - physically contiguous memory request</span></span><br><span class="line"><span class="comment"> * @da: device address</span></span><br><span class="line"><span class="comment"> * @pa: physical address</span></span><br><span class="line"><span class="comment"> * @len: length (in bytes)</span></span><br><span class="line"><span class="comment"> * @flags: iommu protection flags</span></span><br><span class="line"><span class="comment"> * @reserved: reserved (must be zero)</span></span><br><span class="line"><span class="comment"> * @name: human-readable name of the requested memory region</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This resource entry requests the host to allocate a physically contiguous</span></span><br><span class="line"><span class="comment"> * memory region.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * These request entries shonuld precede other firmware resource entries,</span></span><br><span class="line"><span class="comment"> * as other entries might request placing other data objects inside</span></span><br><span class="line"><span class="comment"> * these memory regions (e.g. data/code segments, trace resource entries, ...).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Allocating memory this way helps utilizing the reserved physical memory</span></span><br><span class="line"><span class="comment"> * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries</span></span><br><span class="line"><span class="comment"> * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB</span></span><br><span class="line"><span class="comment"> * pressure is important; it may have a substantial impact on performance.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If the firmware is compiled with static addresses, then @da should specify</span></span><br><span class="line"><span class="comment"> * the expected device address of this memory region. If @da is set to</span></span><br><span class="line"><span class="comment"> * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then</span></span><br><span class="line"><span class="comment"> * overwrite @da with the dynamically allocated address.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * We will always use @da to negotiate the device addresses, even if it</span></span><br><span class="line"><span class="comment"> * isn&#x27;t using an iommu. In that case, though, it will obviously contain</span></span><br><span class="line"><span class="comment"> * physical addresses.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Some remote processors needs to know the allocated physical address</span></span><br><span class="line"><span class="comment"> * even if they do use an iommu. This is needed, e.g., if they control</span></span><br><span class="line"><span class="comment"> * hardware accelerators which access the physical memory directly (this</span></span><br><span class="line"><span class="comment"> * is the case with OMAP4 for instance). In that case, the host will</span></span><br><span class="line"><span class="comment"> * overwrite @pa with the dynamically allocated physical address.</span></span><br><span class="line"><span class="comment"> * Generally we don&#x27;t want to expose physical addresses if we don&#x27;t have to</span></span><br><span class="line"><span class="comment"> * (remote processors are generally _not_ trusted), so we might want to</span></span><br><span class="line"><span class="comment"> * change this to happen _only_ when explicitly required by the hardware.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @flags is used to provide IOMMU protection flags, and @name should</span></span><br><span class="line"><span class="comment"> * (optionally) contain a human readable name of this carveout region</span></span><br><span class="line"><span class="comment"> * (mainly for debugging purposes).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_carveout</span> &#123;</span></span><br><span class="line">u32 da;</span><br><span class="line">u32 pa;</span><br><span class="line">u32 len;</span><br><span class="line">u32 flags;</span><br><span class="line">u32 reserved;</span><br><span class="line">u8 name[<span class="number">32</span>];</span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><h4 id="struct-fw-rsc-devmem">struct fw_rsc_devmem</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_devmem - iommu mapping request</span></span><br><span class="line"><span class="comment"> * @da: device address</span></span><br><span class="line"><span class="comment"> * @pa: physical address</span></span><br><span class="line"><span class="comment"> * @len: length (in bytes)</span></span><br><span class="line"><span class="comment"> * @flags: iommu protection flags</span></span><br><span class="line"><span class="comment"> * @reserved: reserved (must be zero)</span></span><br><span class="line"><span class="comment"> * @name: human-readable name of the requested region to be mapped</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This resource entry requests the host to iommu map a physically contiguous</span></span><br><span class="line"><span class="comment"> * memory region. This is needed in case the remote processor requires</span></span><br><span class="line"><span class="comment"> * access to certain memory-based peripherals; _never_ use it to access</span></span><br><span class="line"><span class="comment"> * regular memory.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This is obviously only needed if the remote processor is accessing memory</span></span><br><span class="line"><span class="comment"> * via an iommu.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @da should specify the required device address, @pa should specify</span></span><br><span class="line"><span class="comment"> * the physical address we want to map, @len should specify the size of</span></span><br><span class="line"><span class="comment"> * the mapping and @flags is the IOMMU protection flags. As always, @name may</span></span><br><span class="line"><span class="comment"> * (optionally) contain a human readable name of this mapping (mainly for</span></span><br><span class="line"><span class="comment"> * debugging purposes).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note: at this point we just &quot;trust&quot; those devmem entries to contain valid</span></span><br><span class="line"><span class="comment"> * physical addresses, but this isn&#x27;t safe and will be changed: eventually we</span></span><br><span class="line"><span class="comment"> * want remoteproc implementations to provide us ranges of physical addresses</span></span><br><span class="line"><span class="comment"> * the firmware is allowed to request, and not allow firmwares to request</span></span><br><span class="line"><span class="comment"> * access to physical addresses that are outside those ranges.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_devmem</span> &#123;</span></span><br><span class="line">u32 da;</span><br><span class="line">u32 pa;</span><br><span class="line">u32 len;</span><br><span class="line">u32 flags;</span><br><span class="line">u32 reserved;</span><br><span class="line">u8 name[<span class="number">32</span>];</span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><h4 id="struct-fw-rsc-trace">struct fw_rsc_trace</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_trace - trace buffer declaration</span></span><br><span class="line"><span class="comment"> * @da: device address</span></span><br><span class="line"><span class="comment"> * @len: length (in bytes)</span></span><br><span class="line"><span class="comment"> * @reserved: reserved (must be zero)</span></span><br><span class="line"><span class="comment"> * @name: human-readable name of the trace buffer</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This resource entry provides the host information about a trace buffer</span></span><br><span class="line"><span class="comment"> * into which the remote processor will write log messages.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @da specifies the device address of the buffer, @len specifies</span></span><br><span class="line"><span class="comment"> * its size, and @name may contain a human readable name of the trace buffer.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * After booting the remote processor, the trace buffers are exposed to the</span></span><br><span class="line"><span class="comment"> * user via debugfs entries (called trace0, trace1, etc..).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_trace</span> &#123;</span></span><br><span class="line">u32 da;</span><br><span class="line">u32 len;</span><br><span class="line">u32 reserved;</span><br><span class="line">u8 name[<span class="number">32</span>];</span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><h4 id="struct-fw-rsc-vdev-vring">struct fw_rsc_vdev_vring</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_vdev_vring - vring descriptor entry</span></span><br><span class="line"><span class="comment"> * @da: device address</span></span><br><span class="line"><span class="comment"> * @align: the alignment between the consumer and producer parts of the vring</span></span><br><span class="line"><span class="comment"> * @num: num of buffers supported by this vring (must be power of two)</span></span><br><span class="line"><span class="comment"> * @notifyid is a unique rproc-wide notify index for this vring. This notify</span></span><br><span class="line"><span class="comment"> * index is used when kicking a remote processor, to let it know that this</span></span><br><span class="line"><span class="comment"> * vring is triggered.</span></span><br><span class="line"><span class="comment"> * @pa: physical address</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This descriptor is not a resource entry by itself; it is part of the</span></span><br><span class="line"><span class="comment"> * vdev resource type (see below).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note that @da should either contain the device address where</span></span><br><span class="line"><span class="comment"> * the remote processor is expecting the vring, or indicate that</span></span><br><span class="line"><span class="comment"> * dynamically allocation of the vring&#x27;s device address is supported.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev_vring</span> &#123;</span></span><br><span class="line">u32 da;</span><br><span class="line">u32 align;</span><br><span class="line">u32 num;</span><br><span class="line">u32 notifyid;</span><br><span class="line">u32 pa;</span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><h4 id="struct-fw-rsc-vdev">struct fw_rsc_vdev</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_vdev - virtio device header</span></span><br><span class="line"><span class="comment"> * @id: virtio device id (as in virtio_ids.h)</span></span><br><span class="line"><span class="comment"> * @notifyid is a unique rproc-wide notify index for this vdev. This notify</span></span><br><span class="line"><span class="comment"> * index is used when kicking a remote processor, to let it know that the</span></span><br><span class="line"><span class="comment"> * status/features of this vdev have changes.</span></span><br><span class="line"><span class="comment"> * @dfeatures specifies the virtio device features supported by the firmware</span></span><br><span class="line"><span class="comment"> * @gfeatures is a place holder used by the host to write back the</span></span><br><span class="line"><span class="comment"> * negotiated features that are supported by both sides.</span></span><br><span class="line"><span class="comment"> * @config_len is the size of the virtio config space of this vdev. The config</span></span><br><span class="line"><span class="comment"> * space lies in the resource table immediate after this vdev header.</span></span><br><span class="line"><span class="comment"> * @status is a place holder where the host will indicate its virtio progress.</span></span><br><span class="line"><span class="comment"> * @num_of_vrings indicates how many vrings are described in this vdev header</span></span><br><span class="line"><span class="comment"> * @reserved: reserved (must be zero)</span></span><br><span class="line"><span class="comment"> * @vring is an array of @num_of_vrings entries of &#x27;struct fw_rsc_vdev_vring&#x27;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This resource is a virtio device header: it provides information about</span></span><br><span class="line"><span class="comment"> * the vdev, and is then used by the host and its peer remote processors</span></span><br><span class="line"><span class="comment"> * to negotiate and share certain virtio properties.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * By providing this resource entry, the firmware essentially asks remoteproc</span></span><br><span class="line"><span class="comment"> * to statically allocate a vdev upon registration of the rproc (dynamic vdev</span></span><br><span class="line"><span class="comment"> * allocation is not yet supported).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note: unlike virtualization systems, the term &#x27;host&#x27; here means</span></span><br><span class="line"><span class="comment"> * the Linux side which is running remoteproc to control the remote</span></span><br><span class="line"><span class="comment"> * processors. We use the name &#x27;gfeatures&#x27; to comply with virtio&#x27;s terms,</span></span><br><span class="line"><span class="comment"> * though there isn&#x27;t really any virtualized guest OS here: it&#x27;s the host</span></span><br><span class="line"><span class="comment"> * which is responsible for negotiating the final features.</span></span><br><span class="line"><span class="comment"> * Yeah, it&#x27;s a bit confusing.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note: immediately following this structure is the virtio config space for</span></span><br><span class="line"><span class="comment"> * this vdev (which is specific to the vdev; for more info, read the virtio</span></span><br><span class="line"><span class="comment"> * spec). the size of the config space is specified by @config_len.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev</span> &#123;</span></span><br><span class="line">u32 id;</span><br><span class="line">u32 notifyid;</span><br><span class="line">u32 dfeatures;</span><br><span class="line">u32 gfeatures;</span><br><span class="line">u32 config_len;</span><br><span class="line">u8 status;</span><br><span class="line">u8 num_of_vrings;</span><br><span class="line">u8 reserved[<span class="number">2</span>];</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev_vring</span> <span class="title">vring</span>[];</span></span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><h4 id="struct-rproc-mem-entry">struct rproc_mem_entry</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rproc_mem_entry - memory entry descriptor</span></span><br><span class="line"><span class="comment"> * @va:virtual address</span></span><br><span class="line"><span class="comment"> * @dma: dma address</span></span><br><span class="line"><span class="comment"> * @len: length, in bytes</span></span><br><span class="line"><span class="comment"> * @da: device address</span></span><br><span class="line"><span class="comment"> * @release: release associated memory</span></span><br><span class="line"><span class="comment"> * @priv: associated data</span></span><br><span class="line"><span class="comment"> * @name: associated memory region name (optional)</span></span><br><span class="line"><span class="comment"> * @node: list node</span></span><br><span class="line"><span class="comment"> * @rsc_offset: offset in resource table</span></span><br><span class="line"><span class="comment"> * @flags: iommu protection flags</span></span><br><span class="line"><span class="comment"> * @of_resm_idx: reserved memory phandle index</span></span><br><span class="line"><span class="comment"> * @alloc: specific memory allocator function</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rproc_mem_entry</span> &#123;</span></span><br><span class="line"><span class="type">void</span> *va;</span><br><span class="line"><span class="type">dma_addr_t</span> dma;</span><br><span class="line"><span class="type">size_t</span> len;</span><br><span class="line">u32 da;</span><br><span class="line"><span class="type">void</span> *priv;</span><br><span class="line"><span class="type">char</span> name[<span class="number">32</span>];</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">node</span>;</span></span><br><span class="line">u32 rsc_offset;</span><br><span class="line">u32 flags;</span><br><span class="line">u32 of_resm_idx;</span><br><span class="line"><span class="type">int</span> (*alloc)(<span class="keyword">struct</span> rproc *rproc, <span class="keyword">struct</span> rproc_mem_entry *mem);</span><br><span class="line"><span class="type">int</span> (*release)(<span class="keyword">struct</span> rproc *rproc, <span class="keyword">struct</span> rproc_mem_entry *mem);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="STM32MP15C-rsc-table-implementation">STM32MP15C rsc_table implementation</h2><p>Taking the<code>STMicroelectronics/STM32CubeMP1</code>repository’s<code>STM32MP157C-EV1</code>as an example:</p><p><code>STM32CubeMP1/Projects/STM32MP157C-EV1/Applications/OpenAMP/OpenAMP_Dynamic_ResMgr/Src/rsc_table.c</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">  ******************************************************************************</span></span><br><span class="line"><span class="comment">  * @file    rsc_table.c</span></span><br><span class="line"><span class="comment">  * @author  MCD Application Team</span></span><br><span class="line"><span class="comment">  * @brief   Ressource table</span></span><br><span class="line"><span class="comment">  *</span></span><br><span class="line"><span class="comment">  *   This file provides a default resource table requested by remote proc to</span></span><br><span class="line"><span class="comment">  *  load the elf file. It also allows to add debug trace using a shared buffer.</span></span><br><span class="line"><span class="comment">  *</span></span><br><span class="line"><span class="comment">  ******************************************************************************</span></span><br><span class="line"><span class="comment">  * @attention</span></span><br><span class="line"><span class="comment">  *</span></span><br><span class="line"><span class="comment">  * Copyright (c) 2021 STMicroelectronics.</span></span><br><span class="line"><span class="comment">  * All rights reserved.</span></span><br><span class="line"><span class="comment">  *</span></span><br><span class="line"><span class="comment">  * This software is licensed under terms that can be found in the LICENSE file</span></span><br><span class="line"><span class="comment">  * in the root directory of this software component.</span></span><br><span class="line"><span class="comment">  * If no LICENSE file comes with this software, it is provided AS-IS.</span></span><br><span class="line"><span class="comment">  *</span></span><br><span class="line"><span class="comment">  ******************************************************************************</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** @addtogroup RSC_TABLE</span></span><br><span class="line"><span class="comment">  * @&#123;</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** @addtogroup resource_table</span></span><br><span class="line"><span class="comment">  * @&#123;</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** @addtogroup resource_table_Private_Includes</span></span><br><span class="line"><span class="comment">  * @&#123;</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(__ICCARM__) || defined (__CC_ARM)</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stddef.h&gt;</span> <span class="comment">/* needed  for offsetof definition*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;rsc_table.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;openamp/open_amp.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">  * @&#125;</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** @addtogroup resource_table_Private_TypesDefinitions</span></span><br><span class="line"><span class="comment">  * @&#123;</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">  * @&#125;</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** @addtogroup resource_table_Private_Defines</span></span><br><span class="line"><span class="comment">  * @&#123;</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Place resource table in special ELF section */</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(__GNUC__)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __section_t(S)          __attribute__((__section__(#S)))</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __resource              __section_t(.resource_table)</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (LINUX_RPROC_MASTER)</span></span><br><span class="line"> <span class="meta">#<span class="keyword">ifdef</span> VIRTIO_MASTER_ONLY</span></span><br><span class="line">  <span class="meta">#<span class="keyword">define</span> CONST</span></span><br><span class="line"> <span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">  <span class="meta">#<span class="keyword">define</span> CONST const</span></span><br><span class="line"> <span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"> <span class="meta">#<span class="keyword">define</span> CONST</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_IPU_C0_FEATURES       1</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> VRING_COUNT         2</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* VirtIO rpmsg device id */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> VIRTIO_ID_RPMSG_            7</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__LOG_TRACE_IO_)</span></span><br><span class="line"><span class="keyword">extern</span> <span class="type">char</span> system_log_buf[];</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(__GNUC__)</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> !defined (__CC_ARM) &amp;&amp; !defined (LINUX_RPROC_MASTER)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Since GCC is not initializing the resource_table at startup, it is declared as volatile to avoid compiler optimization</span></span><br><span class="line"><span class="comment"> * for the CM4 (see resource_table_init() below)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">volatile</span> <span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> __<span class="title">resource</span> __<span class="title">attribute__</span>((<span class="title">used</span>))  <span class="title">resource_table</span>;</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">CONST <span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> __<span class="title">resource</span> __<span class="title">attribute__</span>((<span class="title">used</span>)) <span class="title">resource_table</span> =</span> &#123;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">elif</span> defined(__ICCARM__)</span></span><br><span class="line">__root CONST <span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> <span class="title">resource_table</span> @ &quot;.<span class="title">resource_table</span>&quot; =</span> &#123;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(__ICCARM__) || defined (__CC_ARM) || defined (LINUX_RPROC_MASTER)</span></span><br><span class="line">.version = <span class="number">1</span>,</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__LOG_TRACE_IO_)</span></span><br><span class="line">.num = <span class="number">2</span>,</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">.num = <span class="number">1</span>,</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">.reserved = &#123;<span class="number">0</span>, <span class="number">0</span>&#125;,</span><br><span class="line">.offset = &#123;</span><br><span class="line">offsetof(<span class="keyword">struct</span> shared_resource_table, vdev),</span><br><span class="line">offsetof(<span class="keyword">struct</span> shared_resource_table, cm_trace),</span><br><span class="line">&#125;,</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Virtio device entry */</span></span><br><span class="line">.vdev= &#123;</span><br><span class="line">RSC_VDEV, VIRTIO_ID_RPMSG_, <span class="number">0</span>, RPMSG_IPU_C0_FEATURES, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>,</span><br><span class="line">VRING_COUNT, &#123;<span class="number">0</span>, <span class="number">0</span>&#125;,</span><br><span class="line">&#125;,</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Vring rsc entry - part of vdev rsc entry */</span></span><br><span class="line">.vring0 = &#123;VRING_TX_ADDRESS, VRING_ALIGNMENT, VRING_NUM_BUFFS, VRING0_ID, <span class="number">0</span>&#125;,</span><br><span class="line">.vring1 = &#123;VRING_RX_ADDRESS, VRING_ALIGNMENT, VRING_NUM_BUFFS, VRING1_ID, <span class="number">0</span>&#125;,</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__LOG_TRACE_IO_)</span></span><br><span class="line">.cm_trace = &#123;</span><br><span class="line">RSC_TRACE,</span><br><span class="line">(<span class="type">uint32_t</span>)system_log_buf, SYSTEM_TRACE_BUF_SZ, <span class="number">0</span>, <span class="string">&quot;cm4_log&quot;</span>,</span><br><span class="line">&#125;,</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125; ;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">resource_table_init</span><span class="params">(<span class="type">int</span> RPMsgRole, <span class="type">void</span> **table_ptr, <span class="type">int</span> *length)</span></span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> !defined (LINUX_RPROC_MASTER)</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__GNUC__) &amp;&amp; ! defined (__CC_ARM)</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> VIRTIO_MASTER_ONLY</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * Currently the GCC linker doesn&#x27;t initialize the resource_table global variable at startup</span></span><br><span class="line"><span class="comment">     * it is done here by the master application.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="built_in">memset</span>(&amp;resource_table, <span class="string">&#x27;\0&#x27;</span>, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> shared_resource_table));</span><br><span class="line">resource_table.num = <span class="number">1</span>;</span><br><span class="line">resource_table.version = <span class="number">1</span>;</span><br><span class="line">resource_table.offset[<span class="number">0</span>] = offsetof(<span class="keyword">struct</span> shared_resource_table, vdev);</span><br><span class="line"></span><br><span class="line">resource_table.vring0.da = VRING_TX_ADDRESS;</span><br><span class="line">resource_table.vring0.align = VRING_ALIGNMENT;</span><br><span class="line">resource_table.vring0.num = VRING_NUM_BUFFS;</span><br><span class="line">resource_table.vring0.notifyid = VRING0_ID;</span><br><span class="line"></span><br><span class="line">resource_table.vring1.da = VRING_RX_ADDRESS;</span><br><span class="line">resource_table.vring1.align = VRING_ALIGNMENT;</span><br><span class="line">resource_table.vring1.num = VRING_NUM_BUFFS;</span><br><span class="line">resource_table.vring1.notifyid = VRING1_ID;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">resource_table.vdev.type = RSC_VDEV;</span><br><span class="line">resource_table.vdev.id = VIRTIO_ID_RPMSG_;</span><br><span class="line">resource_table.vdev.num_of_vrings=VRING_COUNT;</span><br><span class="line">resource_table.vdev.dfeatures = RPMSG_IPU_C0_FEATURES;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* For the slave application let&#x27;s wait until the resource_table is correctly initialized */</span></span><br><span class="line"><span class="keyword">while</span>(resource_table.vring1.da != VRING_RX_ADDRESS)</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">  (<span class="type">void</span>)RPMsgRole;</span><br><span class="line">  *length = <span class="keyword">sizeof</span>(resource_table);</span><br><span class="line">  *table_ptr = (<span class="type">void</span> *)&amp;resource_table;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>And the<code>STM32CubeMP1/Projects/STM32MP157C-EV1/Applications/OpenAMP/OpenAMP_Dynamic_ResMgr/Inc/rsc_table.h</code>is as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Copyright (c) 2021 STMicroelectronics.</span></span><br><span class="line"><span class="comment"> * All rights reserved.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This software is licensed under terms that can be found in the LICENSE file</span></span><br><span class="line"><span class="comment"> * in the root directory of this software component.</span></span><br><span class="line"><span class="comment"> * If no LICENSE file comes with this software, it is provided AS-IS.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* This file populates resource table for BM remote</span></span><br><span class="line"><span class="comment"> * for use by the Linux Master */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> RSC_TABLE_H_</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RSC_TABLE_H_</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;openamp/open_amp.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;openamp_conf.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Private includes ----------------------------------------------------------*/</span></span><br><span class="line"><span class="comment">/* USER CODE BEGIN Includes */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* USER CODE END Includes */</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Exported types ------------------------------------------------------------*/</span></span><br><span class="line"><span class="comment">/* USER CODE BEGIN ET */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Resource table for the given remote */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> &#123;</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> version;</span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> num;</span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> reserved[<span class="number">2</span>];</span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> offset[NUM_RESOURCE_ENTRIES];</span><br><span class="line"><span class="comment">/* text carveout entry */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* rpmsg vdev entry */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev</span> <span class="title">vdev</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev_vring</span> <span class="title">vring0</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev_vring</span> <span class="title">vring1</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_trace</span> <span class="title">cm_trace</span>;</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* USER CODE END ET */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Exported constants --------------------------------------------------------*/</span></span><br><span class="line"><span class="comment">/* USER CODE BEGIN EC */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* USER CODE END EC */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Private defines -----------------------------------------------------------*/</span></span><br><span class="line"><span class="comment">/* USER CODE BEGIN Private defines */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* USER CODE END  Private defines */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Exported macro ------------------------------------------------------------*/</span></span><br><span class="line"><span class="comment">/* USER CODE BEGIN EM */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* USER CODE END EM */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Exported functions prototypes ---------------------------------------------*/</span></span><br><span class="line"><span class="comment">/* USER CODE BEGIN EFP */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* USER CODE END EFP */</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">resource_table_init</span><span class="params">(<span class="type">int</span> RPMsgRole, <span class="type">void</span> **table_ptr, <span class="type">int</span> *length)</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* RSC_TABLE_H_ */</span></span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="attribute-marker">attribute marker</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">volatile</span> <span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> __<span class="title">resource</span> __<span class="title">attribute__</span>((<span class="title">used</span>)) <span class="title">resource_table</span>;</span></span><br></pre></td></tr></table></figure><ul><li><p><code>__resource = __attribute__((section(&quot;.resource_table&quot;)))</code></p><ul><li>Place the entire resource_table variable into the<code>.resource_table</code>ELF section.</li><li>This is exactly the section name that the Linux side<code>rproc_elf_load_rsc_table()</code> / <code>rproc_elf_find_loaded_rsc_table() </code>looks for—when the A7 loads the firmware ELF, it locates the resource table by section name.</li></ul></li><li><p><code>resource_table_init() </code>Pass the address and length of this table to the OpenAMP middleware, as the M4’s virtio/rpmsg stack will need them later.</p></li></ul><h3 id="struct-shared-resource-table">struct shared_resource_table</h3><p><code>STM32CubeMP1/Projects/STM32MP157C-EV1/Applications/OpenAMP/OpenAMP_Dynamic_ResMgr/Inc/rsc_table.h</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> &#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> version;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> num;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> reserved[<span class="number">2</span>];</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> offset[NUM_RESOURCE_ENTRIES];   <span class="comment">// NUM_RESOURCE_ENTRIES = 2</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev</span>       <span class="title">vdev</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev_vring</span> <span class="title">vring0</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev_vring</span> <span class="title">vring1</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_trace</span>      <span class="title">cm_trace</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h4 id="struct-fw-rsc-vdev-2">struct fw_rsc_vdev</h4><p><code>STM32CubeMP1/Middlewares/Third_Party/OpenAMP/open-amp/lib/include/openamp/remoteproc.h</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_vdev - virtio device header</span></span><br><span class="line"><span class="comment"> * @id: virtio device id (as in virtio_ids.h)</span></span><br><span class="line"><span class="comment"> * @notifyid is a unique rproc-wide notify index for this vdev. This notify</span></span><br><span class="line"><span class="comment"> * index is used when kicking a remote remoteproc, to let it know that the</span></span><br><span class="line"><span class="comment"> * status/features of this vdev have changes.</span></span><br><span class="line"><span class="comment"> * @dfeatures specifies the virtio device features supported by the firmware</span></span><br><span class="line"><span class="comment"> * @gfeatures is a place holder used by the host to write back the</span></span><br><span class="line"><span class="comment"> * negotiated features that are supported by both sides.</span></span><br><span class="line"><span class="comment"> * @config_len is the size of the virtio config space of this vdev. The config</span></span><br><span class="line"><span class="comment"> * space lies in the resource table immediate after this vdev header.</span></span><br><span class="line"><span class="comment"> * @status is a place holder where the host will indicate its virtio progress.</span></span><br><span class="line"><span class="comment"> * @num_of_vrings indicates how many vrings are described in this vdev header</span></span><br><span class="line"><span class="comment"> * @reserved: reserved (must be zero)</span></span><br><span class="line"><span class="comment"> * @vring is an array of @num_of_vrings entries of &#x27;struct fw_rsc_vdev_vring&#x27;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This resource is a virtio device header: it provides information about</span></span><br><span class="line"><span class="comment"> * the vdev, and is then used by the host and its peer remote remoteprocs</span></span><br><span class="line"><span class="comment"> * to negotiate and share certain virtio properties.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * By providing this resource entry, the firmware essentially asks remoteproc</span></span><br><span class="line"><span class="comment"> * to statically allocate a vdev upon registration of the rproc (dynamic vdev</span></span><br><span class="line"><span class="comment"> * allocation is not yet supported).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note: unlike virtualization systems, the term &#x27;host&#x27; here means</span></span><br><span class="line"><span class="comment"> * the Linux side which is running remoteproc to control the remote</span></span><br><span class="line"><span class="comment"> * remoteprocs. We use the name &#x27;gfeatures&#x27; to comply with virtio&#x27;s terms,</span></span><br><span class="line"><span class="comment"> * though there isn&#x27;t really any virtualized guest OS here: it&#x27;s the host</span></span><br><span class="line"><span class="comment"> * which is responsible for negotiating the final features.</span></span><br><span class="line"><span class="comment"> * Yeah, it&#x27;s a bit confusing.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note: immediately following this structure is the virtio config space for</span></span><br><span class="line"><span class="comment"> * this vdev (which is specific to the vdev; for more info, read the virtio</span></span><br><span class="line"><span class="comment"> * spec). the size of the config space is specified by @config_len.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">METAL_PACKED_BEGIN</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev</span> &#123;</span></span><br><span class="line"><span class="type">uint32_t</span> type;         <span class="comment">// ← ST added type at the very beginning!</span></span><br><span class="line"><span class="type">uint32_t</span> id;</span><br><span class="line"><span class="type">uint32_t</span> notifyid;</span><br><span class="line"><span class="type">uint32_t</span> dfeatures;</span><br><span class="line"><span class="type">uint32_t</span> gfeatures;</span><br><span class="line"><span class="type">uint32_t</span> config_len;</span><br><span class="line"><span class="type">uint8_t</span> status;</span><br><span class="line"><span class="type">uint8_t</span> num_of_vrings;</span><br><span class="line"><span class="type">uint8_t</span> reserved[<span class="number">2</span>];</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev_vring</span> <span class="title">vring</span>[0];</span>  <span class="comment">// Zero-length flexible array</span></span><br><span class="line">&#125; METAL_PACKED_END;</span><br></pre></td></tr></table></figure><p>ST’s<code>fw_rsc_vdev</code>folds type in</p><p>There are two points here:</p><ul><li>ST adds type at the beginning of<code>struct fw_rsc_vdev</code>, while Linux’s struct fw_rsc_vdev does not have type (type is in a separate<code>struct fw_rsc_hdr</code>). But the two are completely identical on-wire:</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ST:    [vdev.type | vdev.id | ... | reserved]  ← type 在 vdev 内</span><br><span class="line">Linux: [hdr.type  | vdev.id | ... | reserved]  ← type 在 hdr 里，vdev 从 id 开始</span><br><span class="line">          byte0      byte4</span><br></pre></td></tr></table></figure><blockquote><p>ST does this so that a designated initializer can initialize the entire vdev entry (including type) at once.</p></blockquote><ul><li><strong>C trick of zero-length vring[0] plus separate vring0/vring1 members</strong></li></ul><p>fw_rsc_vring[0] at the end of vdev occupies 0 bytes, so<code>struct shared_resource_table</code>the vring0 and vring1 members immediately following vdev in memory land right after vdev—exactly where Linux expects to find the vring array. This is equivalent to Linux’s flexible vring[] array, but ST uses separate named members for easier initialization.</p><h4 id="struct-fw-rsc-vdev-vring-2">struct fw_rsc_vdev_vring</h4><p><code>STM32CubeMP1/Middlewares/Third_Party/OpenAMP/open-amp/lib/include/openamp/remoteproc.h</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_vdev_vring - vring descriptor entry</span></span><br><span class="line"><span class="comment"> * @da: device address</span></span><br><span class="line"><span class="comment"> * @align: the alignment between the consumer and producer parts of the vring</span></span><br><span class="line"><span class="comment"> * @num: num of buffers supported by this vring (must be power of two)</span></span><br><span class="line"><span class="comment"> * @notifyid is a unique rproc-wide notify index for this vring. This notify</span></span><br><span class="line"><span class="comment"> * index is used when kicking a remote remoteproc, to let it know that this</span></span><br><span class="line"><span class="comment"> * vring is triggered.</span></span><br><span class="line"><span class="comment"> * @reserved: reserved (must be zero)</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This descriptor is not a resource entry by itself; it is part of the</span></span><br><span class="line"><span class="comment"> * vdev resource type (see below).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note that @da should either contain the device address where</span></span><br><span class="line"><span class="comment"> * the remote remoteproc is expecting the vring, or indicate that</span></span><br><span class="line"><span class="comment"> * dynamically allocation of the vring&#x27;s device address is supported.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">METAL_PACKED_BEGIN</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_vdev_vring</span> &#123;</span></span><br><span class="line"><span class="type">uint32_t</span> da;</span><br><span class="line"><span class="type">uint32_t</span> align;</span><br><span class="line"><span class="type">uint32_t</span> num;</span><br><span class="line"><span class="type">uint32_t</span> notifyid;</span><br><span class="line"><span class="type">uint32_t</span> reserved;</span><br><span class="line">&#125; METAL_PACKED_END;</span><br></pre></td></tr></table></figure><h4 id="struct-fw-rsc-trace-2">struct fw_rsc_trace</h4><p><code>STM32CubeMP1/Middlewares/Third_Party/OpenAMP/open-amp/lib/include/openamp/remoteproc.h</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct fw_rsc_trace - trace buffer declaration</span></span><br><span class="line"><span class="comment"> * @da: device address</span></span><br><span class="line"><span class="comment"> * @len: length (in bytes)</span></span><br><span class="line"><span class="comment"> * @reserved: reserved (must be zero)</span></span><br><span class="line"><span class="comment"> * @name: human-readable name of the trace buffer</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This resource entry provides the host information about a trace buffer</span></span><br><span class="line"><span class="comment"> * into which the remote remoteproc will write log messages.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @da specifies the device address of the buffer, @len specifies</span></span><br><span class="line"><span class="comment"> * its size, and @name may contain a human readable name of the trace buffer.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * After booting the remote remoteproc, the trace buffers are exposed to the</span></span><br><span class="line"><span class="comment"> * user via debugfs entries (called trace0, trace1, etc..).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">METAL_PACKED_BEGIN</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fw_rsc_trace</span> &#123;</span></span><br><span class="line"><span class="type">uint32_t</span> type;</span><br><span class="line"><span class="type">uint32_t</span> da;</span><br><span class="line"><span class="type">uint32_t</span> len;</span><br><span class="line"><span class="type">uint32_t</span> reserved;</span><br><span class="line"><span class="type">uint8_t</span> name[RPROC_MAX_NAME_LEN];</span><br><span class="line">&#125; METAL_PACKED_END;</span><br></pre></td></tr></table></figure><h3 id="rsc-table-instance">rsc_table instance</h3><p><code>STM32CubeMP1/Projects/STM32MP157C-EV1/Applications/OpenAMP/OpenAMP_Dynamic_ResMgr/Src/rsc_table.c</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">if</span> defined(__GNUC__)</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> !defined (__CC_ARM) &amp;&amp; !defined (LINUX_RPROC_MASTER)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Since GCC is not initializing the resource_table at startup, it is declared as volatile to avoid compiler optimization</span></span><br><span class="line"><span class="comment"> * for the CM4 (see resource_table_init() below)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">volatile</span> <span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> __<span class="title">resource</span> __<span class="title">attribute__</span>((<span class="title">used</span>))  <span class="title">resource_table</span>;</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">CONST <span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> __<span class="title">resource</span> __<span class="title">attribute__</span>((<span class="title">used</span>)) <span class="title">resource_table</span> =</span> &#123;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">elif</span> defined(__ICCARM__)</span></span><br><span class="line">__root CONST <span class="class"><span class="keyword">struct</span> <span class="title">shared_resource_table</span> <span class="title">resource_table</span> @ &quot;.<span class="title">resource_table</span>&quot; =</span> &#123;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(__ICCARM__) || defined (__CC_ARM) || defined (LINUX_RPROC_MASTER)</span></span><br><span class="line">.version = <span class="number">1</span>,</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__LOG_TRACE_IO_)</span></span><br><span class="line">.num = <span class="number">2</span>,</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">.num = <span class="number">1</span>,</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">.reserved = &#123;<span class="number">0</span>, <span class="number">0</span>&#125;,</span><br><span class="line">.offset = &#123;</span><br><span class="line">offsetof(<span class="keyword">struct</span> shared_resource_table, vdev),</span><br><span class="line">offsetof(<span class="keyword">struct</span> shared_resource_table, cm_trace),</span><br><span class="line">&#125;,</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Virtio device entry */</span></span><br><span class="line">.vdev= &#123;</span><br><span class="line">RSC_VDEV, VIRTIO_ID_RPMSG_, <span class="number">0</span>, RPMSG_IPU_C0_FEATURES, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>,</span><br><span class="line">VRING_COUNT, &#123;<span class="number">0</span>, <span class="number">0</span>&#125;,</span><br><span class="line">&#125;,</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Vring rsc entry - part of vdev rsc entry */</span></span><br><span class="line">.vring0 = &#123;VRING_TX_ADDRESS, VRING_ALIGNMENT, VRING_NUM_BUFFS, VRING0_ID, <span class="number">0</span>&#125;,</span><br><span class="line">.vring1 = &#123;VRING_RX_ADDRESS, VRING_ALIGNMENT, VRING_NUM_BUFFS, VRING1_ID, <span class="number">0</span>&#125;,</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__LOG_TRACE_IO_)</span></span><br><span class="line">.cm_trace = &#123;</span><br><span class="line">RSC_TRACE,</span><br><span class="line">(<span class="type">uint32_t</span>)system_log_buf, SYSTEM_TRACE_BUF_SZ, <span class="number">0</span>, <span class="string">&quot;cm4_log&quot;</span>,</span><br><span class="line">&#125;,</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">&#125; ;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><h4 id="vdev">vdev</h4><p>Because this project<code>#define LINUX_RPROC_MASTER</code>（<code>openamp_conf.h</code>) takes the static initialization branch:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">.vdev= &#123;</span><br><span class="line">RSC_VDEV,              <span class="comment">// type        = 3</span></span><br><span class="line">       VIRTIO_ID_RPMSG_,      <span class="comment">// id          = 7  (RPMsg device)</span></span><br><span class="line">       <span class="number">0</span>,                     <span class="comment">// notifyid    = 0  (host backfill)</span></span><br><span class="line">       RPMSG_IPU_C0_FEATURES, <span class="comment">// dfeatures   = 1  (bit0 = VIRTIO_RPMSG_F_NS, name service)</span></span><br><span class="line">       <span class="number">0</span>,                     <span class="comment">// gfeatures   = 0  (host backfill negotiation result)</span></span><br><span class="line">       <span class="number">0</span>,                     <span class="comment">// config_len  = 0  (RPMsg has no config space)</span></span><br><span class="line">       <span class="number">0</span>,                     <span class="comment">// status      = 0  (host backfill)</span></span><br><span class="line">VRING_COUNT,           <span class="comment">// num_of_vrings = 2</span></span><br><span class="line">       &#123;<span class="number">0</span>, <span class="number">0</span>&#125;,                <span class="comment">// reserved[2]</span></span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><h4 id="vring"><strong>vring</strong></h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">.vring0 = &#123;VRING_TX_ADDRESS, VRING_ALIGNMENT, VRING_NUM_BUFFS, VRING0_ID, <span class="number">0</span>&#125;,</span><br><span class="line">.vring1 = &#123;VRING_RX_ADDRESS, VRING_ALIGNMENT, VRING_NUM_BUFFS, VRING1_ID, <span class="number">0</span>&#125;,</span><br></pre></td></tr></table></figure><div class="table-wrap"><table><thead><tr><th><strong>vring fields</strong></th><th><strong>vring0 (TX)</strong></th><th><strong>vring1 (RX)</strong></th><th><strong>Description</strong></th></tr></thead><tbody><tr><td><strong>da</strong></td><td>-1 (FW_RSC_ADDR_ANY)</td><td>-1</td><td><strong>Device address</strong>. If -1, it indicates support for dynamically allocating the device address of the vring.</td></tr><tr><td><strong>align</strong></td><td>16</td><td>16</td><td><strong>Alignment size</strong>. The number of alignment bytes between the vring consumer and producer parts.</td></tr><tr><td><strong>num</strong></td><td>16</td><td>16</td><td><strong>Number of buffers</strong>. The number of buffers supported by this vring (must be a power of 2).</td></tr><tr><td><strong>notifyid</strong></td><td>0<br /> (master→remote)</td><td>1<br />(remote→master)</td><td><strong>Notification ID</strong>A unique notification index within the entire remote processor (rproc) scope. When sending a kick signal to the remote side, this ID is used to indicate which vring was triggered.</td></tr><tr><td><strong>reserved</strong></td><td>0</td><td>0</td><td><strong>Reserved field</strong>Must be 0.</td></tr></tbody></table></div><p><code>Dynamic ResMgr</code>The core of:<code>da = -1</code></p><ul><li>Static method: firmware hardcodes<code>vring.da = 0x10040000</code>, Linux uses it directly.</li><li>Dynamic method (<code>STM32CubeMP1/Projects/STM32MP157C-EV1/Applications/OpenAMP/OpenAMP_Dynamic_ResMgr/</code>): firmware writes<code>da = -1</code>, indicating “Linux will allocate”, Linux from the DT<code>vdev0vring0/1</code>reserved<code>carveout</code>pool allocates vring memory, and fills back the real address into<code>vring-&gt;da</code>. Firmware declares requirements, host allocates and fills back — this is exactly the fw_rsc_“negotiation” mentioned in the vdev comment.</li></ul><p><code>openamp_conf.h</code>has two branches:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">if</span> defined LINUX_RPROC_MASTER          <span class="comment">// ← This project takes this branch</span></span></span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> VRING_RX_ADDRESS  ((unsigned int)-1)   <span class="comment">// FW_RSC_ADDR_ANY</span></span></span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> VRING_TX_ADDRESS  ((unsigned int)-1)</span></span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> VRING_ALIGNMENT   16</span></span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> VRING_NUM_BUFFS   16</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span>                                   <span class="comment">// Static allocation when M4 is master</span></span></span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> VRING_RX_ADDRESS  SHM_START_ADDRESS      <span class="comment">// Fixed address</span></span></span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> VRING_TX_ADDRESS  (SHM_START_ADDRESS + 0x400)</span></span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> VRING_ALIGNMENT   4</span></span><br><span class="line">    <span class="meta">#<span class="keyword">define</span> VRING_NUM_BUFFS   4</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><h4 id="cm-trace">cm_trace</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__LOG_TRACE_IO_)</span></span><br><span class="line">.num = <span class="number">2</span>, <span class="comment">// resource entry num</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">.num = <span class="number">1</span>,</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__LOG_TRACE_IO_)</span></span><br><span class="line">.cm_trace = &#123;</span><br><span class="line">RSC_TRACE,                <span class="comment">// type = 2</span></span><br><span class="line">(<span class="type">uint32_t</span>)system_log_buf, <span class="comment">// da = M4 log buffer address (note: real address, not -1)</span></span><br><span class="line">        SYSTEM_TRACE_BUF_SZ,      <span class="comment">// len = 2048  (openamp_log.h)</span></span><br><span class="line">        <span class="number">0</span>,                        <span class="comment">// reserved</span></span><br><span class="line">        <span class="string">&quot;cm4_log&quot;</span>,                <span class="comment">// name → host debugfs file name</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>Note:</p><ul><li>The da of trace is not<code>-1</code></li><li>The trace buffer is allocated by M4 itself (system_log_buf is in M4 memory), host is read-only and does not allocate. After host starts, it will create<code>debugfs/.../cm4_log</code>, and what it reads is the log written by M4.</li></ul><h3 id="resource-table-init">resource_table_init()</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">resource_table_init</span><span class="params">(<span class="type">int</span> RPMsgRole, <span class="type">void</span> **table_ptr, <span class="type">int</span> *length)</span></span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> !defined (LINUX_RPROC_MASTER)</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined (__GNUC__) &amp;&amp; ! defined (__CC_ARM)</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> VIRTIO_MASTER_ONLY</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * Currently the GCC linker doesn&#x27;t initialize the resource_table global variable at startup</span></span><br><span class="line"><span class="comment">     * it is done here by the master application.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="built_in">memset</span>(&amp;resource_table, <span class="string">&#x27;\0&#x27;</span>, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> shared_resource_table));</span><br><span class="line">resource_table.num = <span class="number">1</span>;</span><br><span class="line">resource_table.version = <span class="number">1</span>;</span><br><span class="line">resource_table.offset[<span class="number">0</span>] = offsetof(<span class="keyword">struct</span> shared_resource_table, vdev);</span><br><span class="line"></span><br><span class="line">resource_table.vring0.da = VRING_TX_ADDRESS;</span><br><span class="line">resource_table.vring0.align = VRING_ALIGNMENT;</span><br><span class="line">resource_table.vring0.num = VRING_NUM_BUFFS;</span><br><span class="line">resource_table.vring0.notifyid = VRING0_ID;</span><br><span class="line"></span><br><span class="line">resource_table.vring1.da = VRING_RX_ADDRESS;</span><br><span class="line">resource_table.vring1.align = VRING_ALIGNMENT;</span><br><span class="line">resource_table.vring1.num = VRING_NUM_BUFFS;</span><br><span class="line">resource_table.vring1.notifyid = VRING1_ID;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">resource_table.vdev.type = RSC_VDEV;</span><br><span class="line">resource_table.vdev.id = VIRTIO_ID_RPMSG_;</span><br><span class="line">resource_table.vdev.num_of_vrings=VRING_COUNT;</span><br><span class="line">resource_table.vdev.dfeatures = RPMSG_IPU_C0_FEATURES;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* For the slave application let&#x27;s wait until the resource_table is correctly initialized */</span></span><br><span class="line"><span class="keyword">while</span>(resource_table.vring1.da != VRING_RX_ADDRESS)</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">  (<span class="type">void</span>)RPMsgRole;</span><br><span class="line">  *length = <span class="keyword">sizeof</span>(resource_table);</span><br><span class="line">  *table_ptr = (<span class="type">void</span> *)&amp;resource_table;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>The preprocessor handles three scenarios:</p><div class="table-wrap"><table><thead><tr><th style="text-align:left">Scenario</th><th style="text-align:left">Condition</th><th style="text-align:left">Behavior</th></tr></thead><tbody><tr><td style="text-align:left"><strong>Linux as master</strong><br></td><td style="text-align:left"><code>#ifdef LINUX_RPROC_MASTER</code></td><td style="text-align:left">Skip the entire<code>#if !defined(LINUX_RPROC_MASTER)</code>block; the table is already initialized at compile time, the function only returns:<br /> <code>table_ptr = (void *)&amp;resource_table</code><br /><code>length = sizeof(sizeof(resource_table))</code></td></tr><tr><td style="text-align:left"><strong>GCC + M4 as master</strong></td><td style="text-align:left"><code>GNUC</code> &amp;&amp; <code>!LINUX_RPROC_MASTER</code><br>&amp;&amp; <code>VIRTIO_MASTER_ONLY</code></td><td style="text-align:left">GCC does not initialize global variables with section attributes at startup, so<code>memset</code>after clearing, fill field by field at runtime</td></tr><tr><td style="text-align:left"><strong>GCC + M4 as slave</strong></td><td style="text-align:left"><code>GNUC</code> &amp;&amp; <code>!LINUX_RPROC_MASTER</code></td><td style="text-align:left"><code>while(vring1.da != VRING_RX_ADDRESS)&#123;&#125;</code>spin waiting for master to fill the table</td></tr></tbody></table></div><p>This set of<code>#if</code>nesting is for OpenAMP to be compatible with<code>Linux-master</code> / <code>M4-master</code> / <code>M4-slave</code>three topologies. For STM32MP157 (Linux master), the runtime part is not compiled, it actually only returns a pointer<code>*length = sizeof(resource_table);</code>and<code>*table_ptr = (void *)&amp;resource_table;</code>。</p><blockquote><p>three<code>#if</code>branches indicate who fills the table for this M4 code under the three topologies<code>resource_table</code>: Linux loads (static), M4 master fills at runtime, M4 slave waits to be filled.</p></blockquote><h3 id="Summary">Summary</h3><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/remoteproc/202607041/resource_table.png" alt="resource_table"><figcaption>resource_table</figcaption></figure></p><p>This<code>rsc_table.c</code>This is the “resource requirement list” submitted by the M4 firmware to Linux:</p><ul><li>Declare a<code>virtio-rpmsg</code>device (id=7, 2 vrings, name-service feature)</li><li>a trace buffer, and set the vring address to -1 (<code>FW_RSC_ADDR_ANY</code>) to let Linux dynamically allocate—this is exactly what<code>Dynamic ResMgr</code>means.</li></ul><p>The entire table is placed in the<code>.resource_table</code>ELF section, initialized at compile time,<code>resource_table_init()</code>just passes the pointer to the OpenAMP middleware.</p><h1 id="Storage-and-System-Resource-Allocation">Storage and System Resource Allocation</h1><h2 id="reserved-memory"><code>reserved-memory</code></h2><p>In the<code>stm32mp157d-atk.dtsi</code>device tree, you can see this code:</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">reserved-memory</span> <span class="punctuation">&#123;</span></span><br><span class="line"><span class="meta">#address-cells = &lt;1&gt;;</span></span><br><span class="line"><span class="meta">#size-cells = &lt;1&gt;;</span></span><br><span class="line"><span class="attr">ranges</span><span class="punctuation">;</span></span><br><span class="line"><span class="symbol"></span></span><br><span class="line"><span class="symbol">mcuram2:</span> <span class="title class_">mcuram2@10000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10000000</span> <span class="number">0x40000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        vdev0vring0:</span> <span class="title class_">vdev0vring0@10040000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10040000</span> <span class="number">0x1000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        vdev0vring1:</span> <span class="title class_">vdev0vring1@10041000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10041000</span> <span class="number">0x1000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        vdev0buffer:</span> <span class="title class_">vdev0buffer@10042000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10042000</span> <span class="number">0x4000</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        mcuram:</span> <span class="title class_">mcuram@30000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x30000000</span> <span class="number">0x40000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span> </span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        retram:</span> <span class="title class_">retram@38000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x38000000</span> <span class="number">0x10000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="punctuation">&#125;;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><code>reserved-memory</code>indicates that the memory allocated under this node is reserved memory,<strong>reserved memory regions are generally used by specific drivers, and they differ from the memory regions used by the Linux kernel. Typically, reserved memory functions are closely related to the Linux kernel’s DMA or CMA.</strong></p><blockquote><p>If a node’s<code>compatible</code>the attribute is<code>shared-dma-pool</code>, it indicates that the memory region of this node is used as a DMA buffer shared pool for a group of devices. At this point, if the node attribute contains<code>no-map</code>, it means that this memory cannot be mapped as part of system memory by the Linux kernel and needs to be separated from system memory. If the node attribute contains<code>reusable</code>attribute, it means that this memory does not need to be separated from system memory, and when specific drivers are not using this memory, the OS can use it.</p><p>Note that a node cannot have both the no-map and reusable attributes, as they are logically contradictory.</p></blockquote><p>We see that<code>reserved-memory</code>each child node under the<code>no-map</code>attribute, indicating that this memory cannot be used as system memory by the Linux kernel and is actually reserved for the M4 system.</p><h3 id="mcuram2"><code>mcuram2</code></h3><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="symbol">mcuram2:</span> <span class="title class_">mcuram2@10000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">              <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">              <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10000000</span> <span class="number">0x40000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">              <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">      <span class="punctuation">&#125;;</span></span><br></pre></td></tr></table></figure><p>0x10000000 is the starting address of SRAM1, and the size of 0x40000 is exactly 256KB. This area is the SRAM1+SRAM2 region, mainly used to store the code and data segments of the M4 firmware: SRAM1 (code) and SRAM2 (data). This can be seen from the M4 project’s linker script, but the address range can also be redefined by modifying the linker script. However, note that the address range in the linker script must be consistent with the range configured in the device tree.</p><h3 id="vdev0vring0、vdev0vring1-、vdev0buffer"><code>vdev0vring0</code>、<code>vdev0vring1</code> 、<code>vdev0buffer</code></h3><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="symbol">vdev0vring0:</span> <span class="title class_">vdev0vring0@10040000</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10040000</span> <span class="number">0x1000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line"><span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">vdev0vring1:</span> <span class="title class_">vdev0vring1@10041000</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10041000</span> <span class="number">0x1000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line"><span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">vdev0buffer:</span> <span class="title class_">vdev0buffer@10042000</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10042000</span> <span class="number">0x4000</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">        <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line"><span class="punctuation">&#125;;</span></span><br></pre></td></tr></table></figure><p><code>vdev0vring0</code>、<code>vdev0vring1</code>and<code>vdev0buffer</code>child nodes are exactly at SRAM3, i.e., the IPC buffer. The allocation of these three nodes is as follows:</p><ul><li><code>vdev0vring0</code>child node, 0x10040000 is the starting address of vring0, with an address length of 0x1000, i.e., 4KB. Similarly,</li><li><code>vdev0vring1</code>is the starting address of vring1, also with an address length of 0x1000, i.e., 4KB. These two nodes are the vrings we mentioned earlier for sending and receiving messages.</li><li><code>vdev0buffer</code>child node, with a starting address of 0x10042000, an address length of 0x4000, and a size of 16KB. This address falls within SRAM3, and this is the configured shared memory region.</li></ul><p><code>vdev0vring0</code>、<code>vdev0vring1</code>and<code>vdev0buffer</code>Only the first 24KB of SRAM3 is occupied; SRAM3 has 64KB and is not fully used. Therefore, if needed, the unused addresses of SRAM3 can be repurposed for other functions by modifying the device tree and linker script.</p><h3 id="mcuram"><code>mcuram</code></h3><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="symbol">mcuram:</span> <span class="title class_">mcuram@30000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x30000000</span> <span class="number">0x40000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line"><span class="punctuation">&#125;;</span> </span><br></pre></td></tr></table></figure><p><code>mcuram</code>The child node’s starting address is 0x30000000, with an address length of 0x40000 and a size of 256KB. This address range corresponds to the SRAM1 and SRAM2 areas in RAM aliases. Since the physical addresses of RAM aliases and SRAMs are the same, it is also necessary to configure the corresponding region that is “visible” to the A7; this region corresponds to the one “visible” to the M4.<code>mcuram2</code>region. Because <strong><code>mcuram</code>and<code>mcuram2 </code>have the same physical address, the functions of these two memory regions are identical. It can be said that mcuram is an alias memory region of mcuram2</strong>. This may be the origin of “aliases” in RAM aliases. Note that in the device tree,<code>mcuram</code>and<code>mcuram2</code>the memory segment definitions must be consistent.</p><h3 id="retram"><code>retram</code></h3><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="symbol">retram:</span> <span class="title class_">retram@38000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x38000000</span> <span class="number">0x10000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">        <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line"><span class="punctuation">&#125;;</span></span><br></pre></td></tr></table></figure><p><code>retram</code>The child node’s starting address is 0x38000000, with an address length of 0x10000 (64KB), belonging to the RETRAM area in RAM aliases. This area corresponds to the RETRAM area in the BOOT storage region, and they share the same physical address. RETRAM is used to store the interrupt vector table of the M4 core (the interrupt vector table starts at 0x00000000). By default, the RETRAM starting address is 0x38000000, and it is remapped to 0x00000000 to execute M4 code.</p><h3 id="Summary-2">Summary</h3><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/remoteproc/202607041/sram-address-allocation.png" alt="SRAM Address Allocation"><figcaption>SRAM Address Allocation</figcaption></figure></p><div class="table-wrap"><table><thead><tr><th style="text-align:left">Child Node</th><th style="text-align:left">Address</th><th style="text-align:left">Size</th><th style="text-align:left">Region</th></tr></thead><tbody><tr><td style="text-align:left">mcuram2</td><td style="text-align:left">0x10000000~0x10040000</td><td style="text-align:left">256KB</td><td style="text-align:left">M4-visible SRAM1+SRAM2</td></tr><tr><td style="text-align:left">vdev0vring0</td><td style="text-align:left">0x10040000~0x10041000</td><td style="text-align:left">4KB</td><td style="text-align:left">SRAM3</td></tr><tr><td style="text-align:left">vdev0vring1</td><td style="text-align:left">0x10041000~0x10042000</td><td style="text-align:left">4KB</td><td style="text-align:left">SRAM3</td></tr><tr><td style="text-align:left">vdev0buffer</td><td style="text-align:left">0x10042000~0x10046000</td><td style="text-align:left">16KB</td><td style="text-align:left">SRAM3</td></tr><tr><td style="text-align:left">mcuram</td><td style="text-align:left">0x30000000~0x30040000</td><td style="text-align:left">256KB</td><td style="text-align:left">A7 visible SRAM1+SRAM2</td></tr><tr><td style="text-align:left">retram</td><td style="text-align:left">0x38000000~0x38010000</td><td style="text-align:left">64KB</td><td style="text-align:left">A7 visible RETRAM</td></tr></tbody></table></div><blockquote><p>For unified address management, A7 and M4 may have different address mappings for the same physical address of a real chip. For example, A7 starts from 0X38000000 and this part is called mcuram, while from M4’s perspective it starts from 0X10000000 and this part is called mcuram2. However, these two addresses and their covered lengths ultimately point to the same real memory chip.</p></blockquote><h2 id="m4-system-resources"><code>m4_system_resources</code></h2><p><code>stm32mp151.dtsi</code>Device tree file</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">mlahb</span> <span class="punctuation">&#123;</span> </span><br><span class="line">        <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;simple-bus&quot;</span><span class="punctuation">;</span> </span><br><span class="line">        <span class="meta">#address-cells = &lt;1&gt;; </span></span><br><span class="line">        <span class="meta">#size-cells = &lt;1&gt;; </span></span><br><span class="line">        <span class="attr">dma-ranges</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x00000000</span> <span class="number">0x38000000</span> <span class="number">0x10000</span>&gt;</span>, </span><br><span class="line">                       <span class="params">&lt;<span class="number">0x10000000</span> <span class="number">0x10000000</span> <span class="number">0x60000</span>&gt;</span>, </span><br><span class="line">                       <span class="params">&lt;<span class="number">0x30000000</span> <span class="number">0x30000000</span> <span class="number">0x60000</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        m4_rproc:</span> <span class="title class_">m4@10000000</span> <span class="punctuation">&#123;</span> </span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;st,stm32mp1-m4&quot;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10000000</span> <span class="number">0x40000</span>&gt;</span>, </span><br><span class="line">                       <span class="params">&lt;<span class="number">0x30000000</span> <span class="number">0x40000</span>&gt;</span>, </span><br><span class="line">                       <span class="params">&lt;<span class="number">0x38000000</span> <span class="number">0x10000</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">resets</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;scmi0_reset</span> RST_SCMI0_MCU&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">st,syscfg-holdboot</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;rcc</span> <span class="number">0x10C</span> <span class="number">0x1</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">st,syscfg-tz</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;rcc</span> <span class="number">0x000</span> <span class="number">0x1</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">st,syscfg-rsc-tbl</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;tamp</span> <span class="number">0x144</span> <span class="number">0xFFFFFFFF</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">st,syscfg-copro-state</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;tamp</span> <span class="number">0x148</span> <span class="number">0xFFFFFFFF</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">st,syscfg-pdds</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;pwr_mcu</span> <span class="number">0x0</span> <span class="number">0x1</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;disabled&quot;</span><span class="punctuation">;</span> </span><br><span class="line"> </span><br><span class="line">                <span class="title class_">m4_system_resources</span> <span class="punctuation">&#123;</span> </span><br><span class="line">                        <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;rproc-srm-core&quot;</span><span class="punctuation">;</span> </span><br><span class="line">                        <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;disabled&quot;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="punctuation">&#125;;</span> </span><br><span class="line">        <span class="punctuation">&#125;;</span> </span><br><span class="line"><span class="punctuation">&#125;;</span> </span><br></pre></td></tr></table></figure><p>In the above device tree node, there is a<code>m4_system_resources</code>child node (i.e., M4’s resource manager), which is used to configure M4’s peripheral resources, where<code>compatible</code>in the attribute<code>rproc-srm-core</code>will match the kernel source code’s<code>drivers/remoteproc/rproc_srm_core.c</code>driver file, as follows is the<code>rproc_srm_core.c</code>partial code of the file:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">of_device_id</span> <span class="title">rproc_srm_core_match</span>[] =</span> &#123; </span><br><span class="line">        &#123; .compatible = <span class="string">&quot;rproc-srm-core&quot;</span>, &#125;, </span><br><span class="line">        &#123;&#125;, </span><br><span class="line">&#125;; </span><br><span class="line"> </span><br><span class="line">MODULE_DEVICE_TABLE(of, rproc_srm_core_match); </span><br><span class="line"> </span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">platform_driver</span> <span class="title">rproc_srm_core_driver</span> =</span> &#123; </span><br><span class="line">        .probe = rproc_srm_core_probe, </span><br><span class="line">        .remove = rproc_srm_core_remove,</span><br><span class="line">                .driver = &#123; </span><br><span class="line">                .name = <span class="string">&quot;rproc-srm-core&quot;</span>, </span><br><span class="line">                .of_match_table = of_match_ptr(rproc_srm_core_match), </span><br><span class="line">        &#125;, </span><br><span class="line">&#125;; </span><br><span class="line"> </span><br><span class="line">module_platform_driver(rproc_srm_core_driver);</span><br></pre></td></tr></table></figure><p>After the device and driver match successfully, the function represented by the probe member variable of platform_driver<code>rproc_srm_core_probe()</code>is executed, through which the rproc child device is registered (rproc represents a physical remote processor device, which can be considered a peripheral)</p><p>kernel source code’s<code>stm32mp157-m4-srm.dtsi</code>device tree file, as follows,<code>&amp;m4_rproc</code>indicates in the preceding<code>m4_rproc</code>Append content under the node:</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">&amp;m4_rproc</span> <span class="punctuation">&#123;</span> </span><br><span class="line">  <span class="title class_">m4_system_resources</span> <span class="punctuation">&#123;</span> </span><br><span class="line">    <span class="meta">#address-cells = &lt;1&gt;; </span></span><br><span class="line">    <span class="meta">#size-cells = &lt;0&gt;; </span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">    m4_timers2:</span> <span class="title class_">timer@40000000</span> <span class="punctuation">&#123;</span> </span><br><span class="line">            <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;rproc-srm-dev&quot;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x40000000</span> <span class="number">0x400</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">clocks</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;rcc</span> TIM2_K&gt;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">clock-names</span> <span class="operator">=</span> <span class="string">&quot;int&quot;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;disabled&quot;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="punctuation">&#125;;</span> </span><br><span class="line">    <span class="comment">/* Omit part of the code */</span> </span><br><span class="line"><span class="symbol">     m4_adc:</span> <span class="title class_">adc@48003000</span> <span class="punctuation">&#123;</span> </span><br><span class="line">            <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;rproc-srm-dev&quot;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x48003000</span> <span class="number">0x400</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">clocks</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;rcc</span> ADC12&gt;</span>, <span class="params">&lt;<span class="variable">&amp;rcc</span> ADC12_K&gt;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">clock-names</span> <span class="operator">=</span> <span class="string">&quot;bus&quot;</span>, <span class="string">&quot;adc&quot;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;disabled&quot;</span><span class="punctuation">;</span> </span><br><span class="line">      <span class="punctuation">&#125;;</span> </span><br><span class="line"> </span><br><span class="line">    <span class="comment">/* Omit part of the code */</span> </span><br><span class="line"><span class="symbol">    m4_ethernet0:</span> <span class="title class_">ethernet@5800a000</span> <span class="punctuation">&#123;</span> </span><br><span class="line">            <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;rproc-srm-dev&quot;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x5800a000</span> <span class="number">0x2000</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">clock-names</span> <span class="operator">=</span> <span class="string">&quot;stmmaceth&quot;</span>, </span><br><span class="line">                             <span class="string">&quot;mac-clk-tx&quot;</span>, </span><br><span class="line">                             <span class="string">&quot;mac-clk-rx&quot;</span>, </span><br><span class="line">                             <span class="string">&quot;ethstp&quot;</span>, </span><br><span class="line">                             <span class="string">&quot;syscfg-clk&quot;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">clocks</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;rcc</span> ETHMAC&gt;</span>,</span><br><span class="line">                     <span class="params">&lt;<span class="variable">&amp;rcc</span> ETHTX&gt;</span>, </span><br><span class="line">                     <span class="params">&lt;<span class="variable">&amp;rcc</span> ETHRX&gt;</span>, </span><br><span class="line">                     <span class="params">&lt;<span class="variable">&amp;rcc</span> ETHSTP&gt;</span>, </span><br><span class="line">                     <span class="params">&lt;<span class="variable">&amp;rcc</span> SYSCFG&gt;</span><span class="punctuation">;</span> </span><br><span class="line">            <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;disabled&quot;</span><span class="punctuation">;</span> </span><br><span class="line">    <span class="punctuation">&#125;;</span> </span><br><span class="line">  <span class="punctuation">&#125;;</span> </span><br><span class="line"><span class="punctuation">&#125;;</span></span><br></pre></td></tr></table></figure><p>The above code<strong>configures the system resources of M4, i.e., which peripherals M4 has configured</strong>, however<code>status</code>the attributes are all<code>disabled</code>, meaning although peripherals are configured, they are not enabled.</p><blockquote><p><code>stm32mp157d-atk.dtsi</code>The file includes<code>stm32mp157-m4-srm.dtsi</code>the file</p><p><code>stm32mp157d-atk.dts</code>The file also includes<code>stm32mp157d-atk.dtsi</code>the file</p><p>So you can directly in the<code>stm32mp157d-atk.dtsi</code>or<code>stm32mp157d-atk.dts</code>device tree file choose to enable a certain peripheral of M4.</p></blockquote><p><strong>M4 and A7 share some peripherals</strong>, for example, GPIO is a shared resource. If this GPIO is not multiplexed for other functions and is simply used as a regular IO, then both A7 and M4 can access these resources. For example, in<code>stm32mp157d-atk.dtsi</code>a buzzer and two LED nodes are configured, which use GPIO functions. These nodes are for A7, but M4 can also use them:</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">leds</span> <span class="punctuation">&#123;</span> </span><br><span class="line">   <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;gpio-leds&quot;</span><span class="punctuation">;</span> </span><br><span class="line"> </span><br><span class="line">   <span class="title class_">led1</span> <span class="punctuation">&#123;</span> </span><br><span class="line">       <span class="attr">label</span> <span class="operator">=</span> <span class="string">&quot;sys-led&quot;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">gpios</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;gpioi</span> <span class="number">0</span> GPIO_ACTIVE_LOW&gt;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">linux,default-trigger</span> <span class="operator">=</span> <span class="string">&quot;heartbeat&quot;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">default-state</span> <span class="operator">=</span> <span class="string">&quot;on&quot;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;okay&quot;</span><span class="punctuation">;</span> </span><br><span class="line">   <span class="punctuation">&#125;;</span> </span><br><span class="line"> </span><br><span class="line">   <span class="title class_">led2</span> <span class="punctuation">&#123;</span> </span><br><span class="line">       <span class="attr">label</span> <span class="operator">=</span> <span class="string">&quot;user-led&quot;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">gpios</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;gpiof</span> <span class="number">3</span> GPIO_ACTIVE_LOW&gt;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">linux,default-trigger</span> <span class="operator">=</span> <span class="string">&quot;none&quot;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">default-state</span> <span class="operator">=</span> <span class="string">&quot;on&quot;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;okay&quot;</span><span class="punctuation">;</span> </span><br><span class="line">   <span class="punctuation">&#125;;</span> </span><br><span class="line"> </span><br><span class="line">   <span class="title class_">beep</span> <span class="punctuation">&#123;</span> </span><br><span class="line">       <span class="attr">label</span> <span class="operator">=</span> <span class="string">&quot;beep&quot;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">gpios</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;gpioc</span> <span class="number">7</span> GPIO_ACTIVE_LOW&gt;</span><span class="punctuation">;</span> </span><br><span class="line">       <span class="attr">default-state</span> <span class="operator">=</span> <span class="string">&quot;off&quot;</span><span class="punctuation">;</span> </span><br><span class="line">   <span class="punctuation">&#125;;</span> </span><br><span class="line"><span class="punctuation">&#125;;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>If it is a peripheral with exclusive function, meaning these peripherals can only be used by A7 alone or by M4 alone, if both A7 and M4 use the peripheral together, there will be a resource contention issue, and one side will experience an anomaly (the main processor has a certain priority, and the anomaly usually occurs on the coprocessor side). For example, if A7 and M4 both occupy ADC1 to collect data, the data collected by M4 will be inaccurate, and it may not collect data and display 0.</p><p>For exclusive peripherals:</p><ul><li>If A7 wants to use this peripheral, the corresponding peripheral node for A7 must be configured in the device tree</li><li>If this peripheral is to be used by M4, it is not necessary to configure M4-related nodes in the device tree; you only need to configure the peripheral in the firmware (i.e., configure it in the bare-metal program). After A7 loads and starts the firmware, M4 can use the peripheral.</li></ul><p>If a peripheral node for A7 has already been configured in the device tree, and M4 wants to use this peripheral, it is best to comment out the relevant nodes occupied by A7 in the device tree. For example, in<code>stm32mp157d-atk.dtsi</code>the device tree has the following nodes:</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="symbol">adc1_in6_pins_b:</span> <span class="title class_">adc1-in6</span> <span class="punctuation">&#123;</span> </span><br><span class="line">   <span class="title class_">pins</span> <span class="punctuation">&#123;</span> </span><br><span class="line">       <span class="attr">pinmux</span> <span class="operator">=</span> <span class="params">&lt;STM32_PINMUX(&#x27;A&#x27;, <span class="number">5</span>, ANALOG)&gt;</span><span class="punctuation">;</span> </span><br><span class="line">   <span class="punctuation">&#125;;</span> </span><br><span class="line"><span class="punctuation">&#125;;</span> </span><br><span class="line"> </span><br><span class="line"><span class="variable">&amp;adc</span> <span class="punctuation">&#123;</span> </span><br><span class="line">  <span class="comment">/* ADC1 &amp; ADC2 common resources */</span> </span><br><span class="line">  <span class="attr">pinctrl-names</span> <span class="operator">=</span> <span class="string">&quot;default&quot;</span><span class="punctuation">;</span> </span><br><span class="line">  pinctrl<span class="number">-0</span> = <span class="params">&lt;<span class="variable">&amp;adc1_in6_pins_b</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">      <span class="attr">vdd-supply</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;vdd</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">      <span class="attr">vdda-supply</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;vdd</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">      <span class="attr">vref-supply</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;vdd</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line"> </span><br><span class="line">  <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;okay&quot;</span><span class="punctuation">;</span> </span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">  adc1:</span> <span class="title class_">adc@0</span> <span class="punctuation">&#123;</span> </span><br><span class="line">      <span class="comment">/* private resources for ADC1 */</span> </span><br><span class="line">      <span class="attr">st,adc-channels</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">19</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">      <span class="attr">st,min-sample-time-nsecs</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">10000</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">      <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;okay&quot;</span><span class="punctuation">;</span> </span><br><span class="line">  <span class="punctuation">&#125;;</span> </span><br><span class="line"><span class="punctuation">&#125;;</span> </span><br><span class="line"></span><br></pre></td></tr></table></figure><p>The above code snippet indicates that ADC1 is allocated to A7. If M4 wants to use it, this code does not need to be commented out, as long as it is ensured that A7 does not operate ADC1 after the Linux system runs. Then, after loading and running the M4 firmware (where ADC1 has been configured), M4 can use ADC1 to collect data.</p><p>However, if A7 operates ADC1 at this time, the data collected by ADC1 on the M4 side will be inaccurate. Therefore, it is recommended to comment it out:</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">    adc1_in6_pins_b: adc1-in6 &#123; </span></span><br><span class="line"><span class="comment">         pins &#123; </span></span><br><span class="line"><span class="comment">             pinmux = &lt;STM32_PINMUX(&#x27;A&#x27;, 5, ANALOG)&gt;; </span></span><br><span class="line"><span class="comment">         &#125;; </span></span><br><span class="line"><span class="comment">     &#125;; </span></span><br><span class="line"><span class="comment">*/</span> </span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">&amp;adc &#123; </span></span><br><span class="line"><span class="comment">  //  * ADC1 &amp; ADC2 common resources * </span></span><br><span class="line"><span class="comment">    pinctrl-names = &quot;default&quot;; </span></span><br><span class="line"><span class="comment">    pinctrl-0 = &lt;&amp;adc1_in6_pins_b&gt;; </span></span><br><span class="line"><span class="comment">        vdd-supply = &lt;&amp;vdd&gt;; </span></span><br><span class="line"><span class="comment">        vdda-supply = &lt;&amp;vdd&gt;; </span></span><br><span class="line"><span class="comment">        vref-supply = &lt;&amp;vdd&gt;; </span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment">    status = &quot;okay&quot;; </span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment">    adc1: adc@0 &#123; </span></span><br><span class="line"><span class="comment">    //    * private resources for ADC1 * </span></span><br><span class="line"><span class="comment">        st,adc-channels = &lt;19&gt;; </span></span><br><span class="line"><span class="comment">        st,min-sample-time-nsecs = &lt;10000&gt;; </span></span><br><span class="line"><span class="comment">        status = &quot;okay&quot;; </span></span><br><span class="line"><span class="comment">    &#125;; </span></span><br><span class="line"><span class="comment">&#125;; </span></span><br><span class="line"><span class="comment">*/</span> </span><br><span class="line"><span class="variable">&amp;m4_adc</span> <span class="punctuation">&#123;</span> </span><br><span class="line">        <span class="attr">vref-supply</span> <span class="operator">=</span> <span class="params">&lt;<span class="variable">&amp;vrefbuf</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">        <span class="attr">status</span> <span class="operator">=</span> <span class="string">&quot;okay&quot;</span><span class="punctuation">;</span>            <span class="comment">/* Enable M4&#x27;s ADC */</span> </span><br><span class="line"><span class="punctuation">&#125;;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>That is, comment out the ADC1 part occupied by A7. The following &amp;m4_adc node part is manually added; this part can be added or not, but according to ST’s standard, it is best to add it. The device tree<code>stm32mp157c-dk2-m4-examples.dts</code>is a template file. When modifying the device tree, you can refer to the template file. The above modified<code>&amp;m4_adc</code>node is written by referring to this file.</p><p>After modifying the device tree, execute the following command to recompile the device tree:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs</span><br></pre></td></tr></table></figure><p>Then copy the compiled<code>stm32mp157d-atk.dtb</code>file to the<code>/boot</code>directory of the development board’s file system, replace the previous device tree binary file, then execute the sync command to synchronize the cache, and restart the development board. After re-entering the Linux operating system, the A7 can no longer operate ADC1. When the M4 firmware is loaded and started, the M4 can access ADC1 independently.</p><h2 id="Linker-Script">Linker Script</h2><h3 id="Linker-Script-Syntax">Linker Script Syntax</h3><h4 id="Entry-Address">Entry Address</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Entry Point */</span></span><br><span class="line">ENTRY(Reset_Handler)</span><br></pre></td></tr></table></figure><p><code>ENTRY(SYMBOL)</code>, which means setting the value of the symbol SYMBOL as the entry address, i.e., the address of the first instruction executed by the program.</p><h4 id="Memory-Region-Definition">Memory Region Definition</h4><p>By default, the linker can allocate storage regions at arbitrary positions for sections. The MEMORY command can be used to describe which memory regions can be used by the linker and which should be avoided. A linker script can contain at most one MEMORY command.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">MEMORY </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* Name Attributes Origin Length */</span> </span><br><span class="line">    NAME [(ATTR)] : ORIGIN = ORIGIN, LENGTH = LEN</span><br><span class="line">&#125; </span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><p><strong>NAME</strong>is the name used to reference the memory region in the linker script, each memory region has a unique name</p></li><li><p><strong>ORIGIN</strong>is the starting address</p></li><li><p><strong>LENGTH</strong>is the length of the address</p></li><li><p><strong>ATTR</strong>: an optional attribute string used to restrict which input sections can be placed in this region. Supported characters include:</p><ul><li><strong>r</strong>: Read-only section</li><li><strong>w</strong>: Read/Write section</li><li><strong>x</strong>: Executable section</li><li><strong>a</strong>: Allocatable section</li><li><strong>i</strong>or<strong>l</strong>: Initialized section</li><li><strong>!</strong>: Inverted attribute (indicates placing sections that do not satisfy any attribute after this character)</li></ul></li></ul><p>Usage: Once a memory region is defined, it can be used in section descriptions with<code>&gt;region</code>to instruct the linker to place a specific output section into that region.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">SECTIONS</span><br><span class="line">&#123;</span><br><span class="line">    .text : </span><br><span class="line">    &#123;</span><br><span class="line">        *(.text)</span><br><span class="line">    &#125; &gt; mem</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Section-Link-Definition">Section Link Definition</h4><p>The SECTIONS command is a very important command in linker scripts. Its function is:<strong>Tell the linker how to map input file sections to output file sections, and how to place output sections into the address space.</strong>。</p><p>Like the MEMORY command, there is only one SECTIONS command in a linker script. If there is no SECTIONS command in the entire linker script, the linker will combine all input sections with the same name into one output section, and the order of input sections will be the order in which they are discovered by the linker.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">SECTIONS </span><br><span class="line">&#123; </span><br><span class="line">.text : </span><br><span class="line">&#123; </span><br><span class="line">start.o (.text) <span class="number">6</span> *(.text*) </span><br><span class="line">&#125; &gt;region </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Some common usages:</p><ul><li><p><code>. = ALIGN(4)</code>: Indicates 4-byte address alignment. That is, the starting address of the section must be divisible by 4. Common alignments are ALIGN(4) or ALIGN(8), meaning 4-byte or 8-byte alignment.</p></li><li><p><code>PROVIDE</code>and<code>PROVIDE_HIDDEN</code>Keyword: defines a symbol in the linker script that is not defined by the object file but is referenced by it.</p></li><li><p><code>KEEP()</code>: The function of KEEP() is that when the linker’s<code>–gc-sections</code>garbage collection option is enabled, this part cannot be collected. For example,<code>KEEP(*(.text))</code>indicates that not all .text sections can be treated as garbage for collection.</p></li><li><p><code>/DISCARD/</code>: is a special section name; if used as the output section, all matching sections are discarded.</p></li></ul><p>For more linker script syntax, refer to this site:<div class="tag link"><a class="link-card" title="GNU LD" href="https://even629.com/posts/50001/"><div class="left"><img loading="lazy" src="/images/logo.webp"/></div><div class="right"><p class="text">GNU LD</p><p class="url">https://even629.com/posts/50001/</p></div></a></div></p><h3 id="stm32mp15xx-m4-ld"><code>stm32mp15xx_m4.ld</code></h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">******************************************************************************</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">**  File        : LinkerScript.ld</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">**  Abstract    : Linker script for STM32MP1 series</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">**                Set heap size, stack size and stack location according</span></span><br><span class="line"><span class="comment">**                to application requirements.</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">**                Set memory bank area and size if external memory is used.</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">**  Target      : STMicroelectronics STM32</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">**  Distribution: The file is distributed “as is,” without any warranty</span></span><br><span class="line"><span class="comment">**                of any kind.</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">*****************************************************************************</span></span><br><span class="line"><span class="comment">** @attention</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment">** &lt;h2&gt;&lt;center&gt;&amp;copy; Copyright (c) 2019 STMicroelectronics. </span></span><br><span class="line"><span class="comment">** All rights reserved.&lt;/center&gt;&lt;/h2&gt;</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">** This software component is licensed by ST under BSD 3-Clause license,</span></span><br><span class="line"><span class="comment">** the &quot;License&quot;; You may not use this file except in compliance with the </span></span><br><span class="line"><span class="comment">** License. You may obtain a copy of the License at:</span></span><br><span class="line"><span class="comment">**                       opensource.org/licenses/BSD-3-Clause</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">**</span></span><br><span class="line"><span class="comment">*****************************************************************************</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Entry Point */</span></span><br><span class="line">ENTRY(Reset_Handler)</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Highest address of the user mode stack */</span></span><br><span class="line">_estack = <span class="number">0x10040000</span>;    <span class="comment">/* end of RAM */</span></span><br><span class="line"></span><br><span class="line">_Min_Heap_Size = <span class="number">0x200</span>;      <span class="comment">/* required amount of heap  */</span></span><br><span class="line">_Min_Stack_Size = <span class="number">0x400</span>; <span class="comment">/* required amount of stack */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Memories definition */</span></span><br><span class="line">MEMORY</span><br><span class="line">&#123;</span><br><span class="line">  m_interrupts (RX)  : ORIGIN = <span class="number">0x00000000</span>, LENGTH = <span class="number">0x00000298</span></span><br><span class="line">  m_text       (RX)  : ORIGIN = <span class="number">0x10000000</span>, LENGTH = <span class="number">0x00020000</span></span><br><span class="line">  m_data       (RW)  : ORIGIN = <span class="number">0x10020000</span>, LENGTH = <span class="number">0x00020000</span></span><br><span class="line">  m_ipc_shm    (RW)  : ORIGIN = <span class="number">0x10040000</span>, LENGTH = <span class="number">0x00008000</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Symbols needed for OpenAMP to enable rpmsg */</span></span><br><span class="line">__OPENAMP_region_start__  = ORIGIN(m_ipc_shm);</span><br><span class="line">__OPENAMP_region_end__ = ORIGIN(m_ipc_shm)+LENGTH(m_ipc_shm);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Sections */</span></span><br><span class="line">SECTIONS</span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment">/* The startup code into ROM memory */</span></span><br><span class="line">   <span class="comment">/* Interrupt vector table, placed in RETRAM */</span></span><br><span class="line">  .isr_vector :</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    KEEP(*(.isr_vector)) <span class="comment">/* Startup code */</span></span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  &#125; &gt; m_interrupts</span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">  <span class="comment">/* The program code and other data into ROM memory */</span></span><br><span class="line">  .text :</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    *(.text)           <span class="comment">/* .text sections (code) */</span></span><br><span class="line">    *(.text*)          <span class="comment">/* .text* sections (code) */</span></span><br><span class="line">    *(.glue_7)         <span class="comment">/* glue arm to thumb code */</span></span><br><span class="line">    *(.glue_7t)        <span class="comment">/* glue thumb to arm code */</span></span><br><span class="line">    *(.eh_frame)</span><br><span class="line"></span><br><span class="line">    KEEP (*(.init))</span><br><span class="line">    KEEP (*(.fini))</span><br><span class="line"></span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    _etext = .;        <span class="comment">/* define a global symbols at end of code */</span></span><br><span class="line">  &#125; &gt; m_text</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Constant data into ROM memory*/</span></span><br><span class="line">  .rodata :</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    *(.rodata)         <span class="comment">/* .rodata sections (constants, strings, etc.) */</span></span><br><span class="line">    *(.rodata*)        <span class="comment">/* .rodata* sections (constants, strings, etc.) */</span></span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  &#125; &gt; m_text</span><br><span class="line"></span><br><span class="line">  .ARM.extab   : &#123; </span><br><span class="line">  . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  *(.ARM.extab* .gnu.linkonce.armextab.*)</span><br><span class="line">  . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  &#125; &gt; m_text</span><br><span class="line">  </span><br><span class="line">  .ARM : &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    __exidx_start = .;</span><br><span class="line">    *(.ARM.exidx*)</span><br><span class="line">    __exidx_end = .;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  &#125; &gt; m_text</span><br><span class="line"></span><br><span class="line">  .preinit_array     :</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    PROVIDE_HIDDEN (__preinit_array_start = .);</span><br><span class="line">    KEEP (*(.preinit_array*))</span><br><span class="line">    PROVIDE_HIDDEN (__preinit_array_end = .);</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  &#125; &gt; m_text</span><br><span class="line">  </span><br><span class="line">  .init_array :</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    PROVIDE_HIDDEN (__init_array_start = .);</span><br><span class="line">    KEEP (*(SORT(.init_array.*)))</span><br><span class="line">    KEEP (*(.init_array*))</span><br><span class="line">    PROVIDE_HIDDEN (__init_array_end = .);</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  &#125; &gt; m_text</span><br><span class="line">  </span><br><span class="line">  .fini_array :</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    PROVIDE_HIDDEN (__fini_array_start = .);</span><br><span class="line">    KEEP (*(SORT(.fini_array.*)))</span><br><span class="line">    KEEP (*(.fini_array*))</span><br><span class="line">    PROVIDE_HIDDEN (__fini_array_end = .);</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  &#125; &gt; m_text</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Used by the startup to initialize data */</span></span><br><span class="line">  __DATA_ROM = .;</span><br><span class="line">  _sidata = LOADADDR(.data);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Initialized data sections */</span></span><br><span class="line">  .data :  AT(__DATA_ROM)</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    _sdata = .;        <span class="comment">/* create a global symbol at data start */</span></span><br><span class="line">    *(.data)           <span class="comment">/* .data sections */</span></span><br><span class="line">    *(.data*)          <span class="comment">/* .data* sections */</span></span><br><span class="line"></span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    _edata = .;        <span class="comment">/* define a global symbol at data end */</span></span><br><span class="line">  &#125; &gt; m_data</span><br><span class="line"></span><br><span class="line">  __DATA_END = __DATA_ROM + (_edata - _sdata);</span><br><span class="line">  text_end = ORIGIN(m_text) + LENGTH(m_text);</span><br><span class="line">  ASSERT(__DATA_END &lt;= text_end, <span class="string">&quot;region m_text overflowed with text and data&quot;</span>)</span><br><span class="line"></span><br><span class="line">  .resource_table :</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    KEEP (*(.resource_table*))</span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  &#125; &gt; m_data</span><br><span class="line">  </span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Uninitialized data section into RAM memory */</span></span><br><span class="line">  . = ALIGN(<span class="number">4</span>);</span><br><span class="line">  .bss :</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="comment">/* This is used by the startup in order to initialize the .bss secion */</span></span><br><span class="line">    _sbss = .;         <span class="comment">/* define a global symbol at bss start */</span></span><br><span class="line">    __bss_start__ = _sbss;</span><br><span class="line">    *(.bss)</span><br><span class="line">    *(.bss*)</span><br><span class="line">    *(COMMON)</span><br><span class="line"></span><br><span class="line">    . = ALIGN(<span class="number">4</span>);</span><br><span class="line">    _ebss = .;         <span class="comment">/* define a global symbol at bss end */</span></span><br><span class="line">    __bss_end__ = _ebss;</span><br><span class="line">  &#125; &gt; m_data</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* User_heap_stack section, used to check that there is enough RAM left */</span></span><br><span class="line">  ._user_heap_stack :</span><br><span class="line">  &#123;</span><br><span class="line">    . = ALIGN(<span class="number">8</span>);</span><br><span class="line">    PROVIDE ( end = . );</span><br><span class="line">    PROVIDE ( _end = . );</span><br><span class="line">    . = . + _Min_Heap_Size;</span><br><span class="line">    . = . + _Min_Stack_Size;</span><br><span class="line">    . = ALIGN(<span class="number">8</span>);</span><br><span class="line">  &#125; &gt; m_data</span><br><span class="line"></span><br><span class="line">  </span><br><span class="line"></span><br><span class="line">  <span class="comment">/* Remove information from the compiler libraries */</span></span><br><span class="line">  /DISCARD/ :</span><br><span class="line">  &#123;</span><br><span class="line">    libc.a ( * )</span><br><span class="line">    libm.a ( * )</span><br><span class="line">    libgcc.a ( * )</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  .ARM.attributes <span class="number">0</span> : &#123; *(.ARM.attributes) &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Analysis:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Entry Point */</span></span><br><span class="line">ENTRY(Reset_Handler)</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Highest address of the user mode stack */</span></span><br><span class="line">_estack = <span class="number">0x10040000</span>;    <span class="comment">/* end of RAM */</span></span><br><span class="line"></span><br><span class="line">_Min_Heap_Size = <span class="number">0x200</span>;      <span class="comment">/* required amount of heap  */</span></span><br><span class="line">_Min_Stack_Size = <span class="number">0x400</span>; <span class="comment">/* required amount of stack */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Memories definition */</span></span><br><span class="line">MEMORY</span><br><span class="line">&#123;</span><br><span class="line">  m_interrupts (RX)  : ORIGIN = <span class="number">0x00000000</span>, LENGTH = <span class="number">0x00000298</span></span><br><span class="line">  m_text       (RX)  : ORIGIN = <span class="number">0x10000000</span>, LENGTH = <span class="number">0x00020000</span></span><br><span class="line">  m_data       (RW)  : ORIGIN = <span class="number">0x10020000</span>, LENGTH = <span class="number">0x00020000</span></span><br><span class="line">  m_ipc_shm    (RW)  : ORIGIN = <span class="number">0x10040000</span>, LENGTH = <span class="number">0x00008000</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Symbols needed for OpenAMP to enable rpmsg */</span></span><br><span class="line">__OPENAMP_region_start__  = ORIGIN(m_ipc_shm);</span><br><span class="line">__OPENAMP_region_end__ = ORIGIN(m_ipc_shm)+LENGTH(m_ipc_shm);</span><br></pre></td></tr></table></figure><ol><li><p><strong>Core Configuration Analysis</strong></p><ul><li><p><strong>Program Entry</strong>: Specifies<code>Reset_Handler</code>as the program entry; this function is defined in the startup file<code>startup_stm32mp15xx.s</code>.</p></li><li><p><strong>Stack Top Address</strong>: Set the highest stack address to<code>0x10040000</code>. It determines the initial position of the stack pointer (SP), corresponding to the mapping boundary of the internal SRAM.</p></li><li><p><strong>Stack size</strong>: Specify the minimum space. The heap size is<strong>512B</strong>, the stack size is<strong>1KB</strong>。</p></li></ul></li><li><p><strong>Memory region (MEMORY) definition</strong></p><ul><li><p><strong><code>m_interrupts</code>(0x00000000 ~ 0x00000298)</strong>: Mapped to the RETRAM region, used to store the interrupt vector table of the M4 core.</p></li><li><p><strong><code>m_text</code> (0x10000000 ~ 0x10020000)</strong>: Corresponds to <strong>SRAM1 (128KB)</strong>, used to store the code segment.</p></li><li><p><strong><code>m_data</code> (0x10020000 ~ 0x10040000)</strong>: Corresponds to <strong>SRAM2 (128KB)</strong>, used to store the data segment.</p></li></ul></li></ol><blockquote><p>The linker script plans the program execution address in SRAM:</p></blockquote><ol start="3"><li><strong>SRAM allocation logic under dual-core collaboration</strong></li></ol><p>The total SRAM space available to M4 is<strong>SRAM1 ~ SRAM4 (384KB total)</strong>, address range<code>0x10000000 ~ 0x1005FFFF</code>. When allocating, pay attention to the operating mode:</p><ul><li><strong>Single-core mode (M4 only)</strong>: SRAM1 ~ SRAM4 can be fully allocated to M4.</li><li><strong>Dual-core mode (A7 + M4)</strong>：<ul><li><strong>SRAM1 &amp; SRAM2</strong>: Fully allocated to M4 (stores M4 code and data).</li><li><strong>SRAM3</strong>: Shared by A7 and M4. Among them,<code>0x10040000 ~ 0x10046000</code>is used by default as<strong>the memory swap area for dual-core communication (IPC Shared Memory)</strong>. The specific allocation ratio needs to refer to the Device Tree configuration under Linux.</li></ul></li></ul><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">reserved-memory</span> <span class="punctuation">&#123;</span></span><br><span class="line"><span class="meta">#address-cells = &lt;1&gt;;</span></span><br><span class="line"><span class="meta">#size-cells = &lt;1&gt;;</span></span><br><span class="line"><span class="attr">ranges</span><span class="punctuation">;</span></span><br><span class="line"><span class="symbol"></span></span><br><span class="line"><span class="symbol">mcuram2:</span> <span class="title class_">mcuram2@10000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10000000</span> <span class="number">0x40000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        vdev0vring0:</span> <span class="title class_">vdev0vring0@10040000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10040000</span> <span class="number">0x1000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        vdev0vring1:</span> <span class="title class_">vdev0vring1@10041000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10041000</span> <span class="number">0x1000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        vdev0buffer:</span> <span class="title class_">vdev0buffer@10042000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x10042000</span> <span class="number">0x4000</span>&gt;</span><span class="punctuation">;</span> </span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        mcuram:</span> <span class="title class_">mcuram@30000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x30000000</span> <span class="number">0x40000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span> </span><br><span class="line"><span class="symbol"> </span></span><br><span class="line"><span class="symbol">        retram:</span> <span class="title class_">retram@38000000</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="attr">compatible</span> <span class="operator">=</span> <span class="string">&quot;shared-dma-pool&quot;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">reg</span> <span class="operator">=</span> <span class="params">&lt;<span class="number">0x38000000</span> <span class="number">0x10000</span>&gt;</span><span class="punctuation">;</span></span><br><span class="line">                <span class="attr">no-map</span><span class="punctuation">;</span></span><br><span class="line">        <span class="punctuation">&#125;;</span></span><br><span class="line"><span class="punctuation">&#125;;</span></span><br></pre></td></tr></table></figure><p>And m_interrupts is actually in RETRAM, what is the remaining SRAM4 used for?</p><ul><li><p>If not running the Linux operating system, but only running M4 bare-metal programs, the M4 core can fully use this area, as specified by the user.</p></li><li><p>If running the Linux operating system, under the Linux device tree, SRAM4 is already used by default as DMA for Linux functions. To release this area, delete the corresponding node in the device tree (but this is not recommended, as the A7 may malfunction).</p></li></ul><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/remoteproc/202607041/sram-regions.png" alt="Several SRAM areas"><figcaption>Several SRAM areas</figcaption></figure></p><p>Based on the above analysis, the summary is as follows:</p><ul><li>If not running A7, only running M4 (M4 can run bare metal, RTOS): SRAM1~SRAM4 can be fully allocated to M4;</li><li>If running both A7 and M4 (e.g., dual-core communication): SRAM1 and SRAM2 are exclusively for M4, part of SRAM3 is shared between M4 and A7, and SRAM4 is configured separately for DMA under Linux, meaning it is occupied by A7. If you need to modify the address range in MEMORY, be sure to refer to the address range of the memory map table for modification.</li></ul><h1 id="Reference-Materials">Reference Materials</h1><div class="reference-source"><span class="hidden-anchor" id="referfrom_[1]"></span><a class="reference-anchor" href="#referto_[1]">[1]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Remoteproc Brief Analysis of Related Drivers ---- Resource Table" href=" https://blog.csdn.net/qq_54050349/article/details/154799522">Remoteproc Brief Analysis of Related Drivers ---- Resource Table</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[2]"></span><a class="reference-anchor" href="#referto_[2]">[2]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Remoteproc Brief Analysis of Related Drivers ---- Storage and System Resource Allocation" href=" https://blog.csdn.net/qq_54050349/article/details/154804306">Remoteproc Brief Analysis of Related Drivers ---- Storage and System Resource Allocation</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[3]"></span><a class="reference-anchor" href="#referto_[3]">[3]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Remoteproc Brief Analysis of Related Drivers ---- Linker Script" href=" https://blog.csdn.net/qq_54050349/article/details/154834025">Remoteproc Brief Analysis of Related Drivers ---- Linker Script</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[4]"></span><a class="reference-anchor" href="#referto_[4]">[4]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="ALIENTEKSTM32MP157Core Board" href=" http://47.111.11.73/docs/boards/arm-linux/zdyzmp157hxb.html">ALIENTEKSTM32MP157Core Board</a></div>]]></content>
    
    
    <summary type="html">This article introduces the structure and function of the resource table in the remote processor firmware image, detailing how the main processor, after loading the firmware, decodes the resource table to allocate system resources such as physical memory, configure Virtio devices, and create RPMsg channels for inter-core communication. Additionally, using the STM32MP15C reference code, it summarizes the specific definitions of resource entries under the Remoteproc framework and the implementation of dynamic resource management based on OpenAMP.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>OpenAMP</title>
    <link href="https://even629.com/en/posts/202607040/"/>
    <id>https://even629.com/en/posts/202607040/</id>
    <published>2026-07-04T08:17:13.000Z</published>
    <updated>2026-07-04T08:17:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-07-04</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the background of the OpenAMP open asymmetric multiprocessing software framework and its application in multi-core heterogeneous systems. It discusses in detail the three core components: Virtio, RPMsg, and Remoteproc, and summarizes the specific working mechanism for lifecycle management and message communication between the Linux main processor and bare-metal or RTOS coprocessors based on shared memory and inter-core interrupts.</blockquote><hr><p>OpenAMP (Open Asymmetric Multiprocessing) was originally developed by Mentor Graphics and Xilinx as a software framework to enable communication between RTOS or bare-metal programs and the Linux interface in AMP systems. Currently, OpenAMP is available on platforms such as ST, NXP, TI, and Xilinx. These manufacturers have provided ported OpenAMP development examples, and users can refer to these examples for development. This article uses<code>STM32Cube_FW_MP1_V1.2.0\Projects\STM32MP157C-DK2\Applications\OpenAMP</code>as a reference example.</p><p><strong>OpenAMP Project Official Website</strong></p><div class="tag link"><a class="link-card" title="OpenAMP Project" href="https://www.openampproject.org/"><div class="left"><img loading="lazy" src="https://www.openampproject.org/favicon.png"/></div><div class="right"><p class="text">OpenAMP Project</p><p class="url">https://www.openampproject.org/</p></div></a></div> <p><strong>OpenAMP Official Documentation</strong></p><div class="tag link"><a class="link-card" title="OpenAMP Project Documentation" href="https://openamp.readthedocs.io/en/latest/index.html"><div class="left"><img loading="lazy" src="https://openamp.readthedocs.io/favicon.ico"/></div><div class="right"><p class="text">OpenAMP Project Documentation</p><p class="url">https://openamp.readthedocs.io/en/latest/index.html</p></div></a></div> <p><strong>OpenAMP Github Open Source Repository</strong></p><div class="tag link"><a class="link-card" title="OpenAMP" href="https://github.com/OpenAMP"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">OpenAMP</p><p class="url">https://github.com/OpenAMP</p></div></a></div> <p><strong>The main OpenAMP library</strong> (implementing RPMSG, Virtio, and Remoteproc for RTOS etc)</p><div class="tag link"><a class="link-card" title="open-amp" href="https://github.com/OpenAMP/open-amp"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">open-amp</p><p class="url">https://github.com/OpenAMP/open-amp</p></div></a></div> <p><strong>STM32CubeMP1 MPU Firmware Package</strong></p><ul><li>STM32MP157C-EV1 RevC</li><li>STM32MP157C-DK2 RevC</li></ul><div class="tag link"><a class="link-card" title="STM32CubeMP1" href="https://github.com/STMicroelectronics/STM32CubeMP1/"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">STM32CubeMP1</p><p class="url">https://github.com/STMicroelectronics/STM32CubeMP1/</p></div></a></div> <p>OpenAMP provides implementations of RPMsg, VirtIO, and RemoteProc:</p><h2 id="virtio">virtio</h2><p>Virtio is a virtual device framework that provides shared memory management. The vring in Virtio is a FIFO queue of pointers to data buffers, with two unidirectional vrings:</p><ul><li>One vring is dedicated to messages sent to the remote processor</li><li>The other vring is used for messages received from the remote processor</li></ul><p>The two vrings form a ring. Data between the A7 and M4 is shared through the vring buffers, which are the shared memory of the two processors (also known as IPC Buffers or Vring buffers)</p><p>In the reference configuration provided by ST, the shared memory of the STM32MP157 is located in SRAM3. As shown in the figure below, the processors complete data forwarding through the vring ring buffer.<br><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607040/virtio-vring-data-forwarding.png" alt="Virtio vring data forwarding"><figcaption>Virtio vring data forwarding</figcaption></figure></p><p>The relevant code is located at<code>linux-5.10.256/drivers/virtio</code></p><h2 id="rpmsg">rpmsg</h2><p>The RPMsg framework is shown in the figure below. It can be seen that the RPMsg framework sits on top of Virtio. RPMsg (Remote<br>Processor Messaging) framework is a message bus based on Virtio. RPMsg can communicate messages with the remote end via Virtio under the coordination of IPCC, while Remote proc can write firmware to the remote end under the control of IPCC, or control the lifecycle, status, etc. of the remote end.</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607040/rpmsg-framework-diagram.png" alt="Schematic diagram of the Rpmsg framework"><figcaption>Schematic diagram of the Rpmsg framework</figcaption></figure></p><p>From the figure, it can be seen that OpenAMP uses IPCC at the bottom layer. Reference:</p><div class="tag link"><a class="link-card" title="IPCC" href="https://even629.com/posts/202607020/"><div class="left"><img loading="lazy" src="/images/logo.webp"/></div><div class="right"><p class="text">IPCC</p><p class="url">https://even629.com/posts/202607020/</p></div></a></div> <p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/shared/06.png" alt="Block diagram of IPC communication structure"><figcaption>Block diagram of IPC communication structure</figcaption></figure></p><p>On Cortex-A7, the RemoteProc framework activates Linux-based inter-process communication (IPC) based on available information in the coprocessor’s firmware resource table. The RPMsg service is implemented through the RPMsg framework, and the mailbox service is implemented by the mailbox driver stm32_ipcc.</p><p>On Cortex-M4, the RPMsg service is implemented by the OpenAMP library, and the mailbox service is implemented by the HAL_IPCC driver.</p><blockquote><p>This is a bit convoluted. The general idea is that the A core running Linux and the M core running bare metal or FreeRTOS communicate via OpenAMP. The A core and M core have correspondingly designed OpenAMP, but they are compatible with each other, only the underlying calls differ, such as the A core’s mailbox driver stm32_ipcc implementation, and the M core’s mailbox service is implemented by HAL_IPCC driver.</p></blockquote><p>In the default configuration provided by ST, the SRAM3 area in MCUSRAM has two vrings, one for sending and one for receiving messages. The vring buffers are the shared memory. The RPMsg framework is based on Virtio’s vrings. It sends messages to or receives messages from the remote processor through Virtio’s vrings. When a new message is already in the shared memory, the mailbox framework notifies the processor that there is a message to receive.</p><p><strong>RPMsg is actually a message bus based on Virtio</strong>, used to implement message passing (transferring inter-core data). RPMsg can be considered a channel for communicating with a remote processor. This channel can also be called an RPMsg device. Each channel has a local source address and a remote destination address, and messages can be transmitted between the source and destination addresses. The communication process is shown in the figure below:</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607040/communication-process-diagram.png" alt="Communication process diagram"><figcaption>Communication process diagram</figcaption></figure></p><p>Regarding RPMsg, refer to:</p><div class="tag link"><a class="link-card" title="Rpmsg Char Driver" href="https://even629.com/posts/202606290/"><div class="left"><img loading="lazy" src="/images/logo.webp"/></div><div class="right"><p class="text">Rpmsg Char Driver</p><p class="url">https://even629.com/posts/202606290/</p></div></a></div> <div class="tag link"><a class="link-card" title="Rpmsg Core" href="https://even629.com/posts/202606270/"><div class="left"><img loading="lazy" src="/images/logo.webp"/></div><div class="right"><p class="text">Rpmsg Core</p><p class="url">https://even629.com/posts/202606270/</p></div></a></div> <div class="tag link"><a class="link-card" title="Virtio Rpmsg Bus" href="https://even629.com/posts/202606230/"><div class="left"><img loading="lazy" src="/images/logo.webp"/></div><div class="right"><p class="text">Virtio Rpmsg Bus</p><p class="url">https://even629.com/posts/202606230/</p></div></a></div> <p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/shared/05.png" alt="rpmsg.drawio"><figcaption>rpmsg.drawio</figcaption></figure></p><p>Based on these software frameworks, all data is transmitted over RPMsg. RPMsg transfers data to the RPMsg client in the kernel layer, and then to user space through device nodes under the kernel. In relation to the hierarchical structure of the network TCP/IP, shared memory and inter-core interrupts correspond to the physical hardware layer, Virtio corresponds to the MAC sublayer, and RPMsg corresponds to the transport layer, as shown in the following figure:</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607040/rpmsg-tcp-ip-analogy.png" alt="RPMsg analogy to TCP/IP structural relationship"><figcaption>RPMsg analogy to TCP/IP structural relationship</figcaption></figure></p><h2 id="remoteproc">remoteproc</h2><p>For SOCs with asymmetric multiprocessing, different cores may run different operating systems. For example, the Cortex-A7 of the STM32MP157 runs the Linux operating system, while the Cortex-M4 can run the OneOS operating system or bare-metal programs.</p><p>To facilitate easy communication between the main processor running Linux and the coprocessor, the Remoteproc inter-core communication framework was introduced after Linux version 3.4.X. The Remoteproc framework was developed by Texas Instruments, and based on it, Mentor Graphics developed a software framework called OpenAMP. Under this framework, the Linux operating system on the main processor can manage the lifecycle of the remote processor and its associated software environment, i.e., start or shut down the remote processor.</p><p>Let’s take the STM32MP157 as an example to look at the Remoteproc framework for M4 and A7, as shown in the following figure:</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607040/remoteproc-framework.png" alt="Remoteproc framework"><figcaption>Remoteproc framework</figcaption></figure></p><p>Remoteproc is part of the generic remote processing framework, and its functions are:</p><ol><li>A7 loads the code and data segments of the M4 firmware image into M4 memory for in-place program execution;</li><li>Parse the firmware resource table to set associated resources (information such as the starting address and size of each segment in the firmware, Virtio device features, vring address, size, and alignment information);</li><li>Control the start and shutdown of the M4 core firmware;</li><li>Establish RPMsg communication channels for communication with M4;</li><li>Provide monitoring and debugging remote services (using sysfs and debugfs file systems, which are already configured by default in the development board’s Linux file system and are ready to use on boot).</li></ol><blockquote><p>Note: RPMsg communication uses Mailbox, but this is not well illustrated in the figure. Therefore, the general process can be understood as: Remoteproc can directly map the firmware to the M core, and message passing requires communication through channels established after initialization. In the figure, RCC and others are configured automatically via stm32 after the firmware image._rproc will automatically configure, i.e., stm32_rproc is the post-sales of Remoteproc, performing a series of subsequent operations.</p></blockquote><p>stm32_rproc is the driver for the remote processor (M4 core), and its role is:</p><ol><li>Register vendor-specific functions (such as callback functions) with the Remoteproc framework;</li><li>Handle platform resources associated with the M4 (such as registers, watchdog, reset, clock, and memory);</li><li>Forward notifications to the M4 via the Mailbox framework.</li></ol><p>The firmware mentioned above is the executable file for the M4, such as the one compiled under MDK<code>.axf</code>file or the one compiled under STM32CubeIDE<code>.elf</code>file.</p><p>The A7 is called the main processor, and the M4 is called the coprocessor or remote processor. The main processor starts first, then boots the coprocessor:</p><ul><li>The main processor can first load the coprocessor’s firmware via the Remoteproc framework, then parse the information published in the firmware resource table to configure the coprocessor’s system resources and create Virtio devices.</li><li>Once the Remoteproc on the main processor loads and starts the remote processor’s firmware, the coprocessor begins to run.</li><li>After the coprocessor starts, inter-core communication between the two cores is not yet possible. An RPMsg channel must first be created, and only after the main processor sends the first message can inter-core communication occur and data be exchanged.</li><li>If the firmware needs to be stopped, the main processor can also shut down the firmware, and the coprocessor program will then stop running. In summary, the Remoteproc framework implements lifecycle management (LCM) and control of the remote coprocessor, as shown in the following diagram:</li></ul><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607040/remoteproc-control-coprocessor.png" alt="Remoteproc controls the coprocessor"><figcaption>Remoteproc controls the coprocessor</figcaption></figure></p><p>The relevant code is located at<code>linux-5.10.256/drivers/remoteproc</code></p><h2 id="Summary">Summary</h2><p>Based on the above analysis, the OpenAMP open-source software framework has the following functions and features:</p><ul><li>Provides remote processor lifecycle management and inter-processor communication functions;</li><li>Provides independent libraries usable in RTOS and bare-metal software environments;</li><li>Compatible with upstream Linux Remoteproc, RPMsg, and VirtIO components.</li></ul><p>The process of implementing inter-core communication using OpenAMP:</p><blockquote><p>Assume the main processor is already running and the remote processor is in a certain state, such as standby or powered off.</p></blockquote><ol><li>The main processor, based on the Remoteproc framework, first loads the firmware of the remote processor into memory.</li><li>Then the main processor starts the remote processor (runs the firmware) and waits for it to complete initialization, such as waking up, de-asserting reset, powering on, etc.</li><li>After the remote processor completes initialization, it notifies the main processor.</li><li>The main processor and the remote processor establish an RPMsg communication channel.</li><li>Through the RPMsg channel, the two can perform inter-core communication.</li></ol><h2 id="References">References</h2><div class="reference-source"><span class="hidden-anchor" id="referfrom_[1]"></span><a class="reference-anchor" href="#referto_[1]">[1]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="【STM32MP157 Heterogeneous Core Communication Framework Learning】（3）OpenAMPFramework" href="https://blog.csdn.net/qq_54050349/article/details/154772235?spm=1011.2415.3001.5331">【STM32MP157 Heterogeneous Core Communication Framework Learning】（3）OpenAMPFramework</a></div>]]></content>
    
    
    <summary type="html">This article introduces the background of the OpenAMP open asymmetric multiprocessing software framework and its application in multi-core heterogeneous systems. It discusses in detail the three core components: Virtio, RPMsg, and Remoteproc, and summarizes the specific working mechanism for lifecycle management and message communication between the Linux main processor and bare-metal or RTOS coprocessors based on shared memory and inter-core interrupts.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>IPCC</title>
    <link href="https://even629.com/en/posts/202607020/"/>
    <id>https://even629.com/en/posts/202607020/</id>
    <published>2026-07-02T15:17:13.000Z</published>
    <updated>2026-07-02T15:17:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-07-02</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the working principle of the IPCC (Inter-Processor Communication Controller) hardware module in the STM32MP157, discusses its process of achieving signal notification between the Cortex-A7 and Cortex-M4 cores through shared memory and hardware interrupt mechanisms, and summarizes the channel allocation, software framework application, and related register configuration of the IPCC.</blockquote><hr><p><strong>IPC</strong>（ <strong>Inter -Process Communication</strong>, inter-process communication) refers to the interaction between data of two processes (in a broad sense, including processes on heterogeneous cores), which is achieved through the inter-processor communication controller<strong>IPCC</strong>（<strong>Inter-Process Communication controller</strong>, IPC controller). The IPCC is a hardware component used for signal exchange between two CPUs. Mailboxes rely on the IPCC. The IPCC hardware module of the STM32MP157 has 6 bidirectional channels, each divided into two sub-channels, resulting in a total of 12 sub-channels. The figure shows a structural diagram of communication between the A7 core and M4 core via the IPCC.</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/shared/06.png" alt="IPC Communication Structure Diagram"><figcaption>IPC Communication Structure Diagram</figcaption></figure></p><p><strong>When a data packet is placed into shared memory, the CPU needs to interrupt or “notify” the other CPU that there is a new data packet in shared memory to be processed. The other CPU then processes it upon receiving the signal. This is accomplished using the IPCC hardware interrupt mechanism.</strong>。</p><p>The interrupt controller for the A7 core is the GIC, and for the M4 core it is the NVIC. The role of the IPCC is like a sentinel, controlling when data can be received and when data can be sent; the entire process is managed by the IPCC.</p><p><strong>The IPCC only provides a mechanism for information exchange between processors; it does not have data transmission functionality.</strong>, that is,<strong>the data to be exchanged between processors</strong>is not transmitted within the IPCC,<strong>but is transmitted in shared memory.</strong>。</p><h2 id="IPCC-Channels">IPCC Channels</h2><p>The working modes of the IPCC’s 6 communication channels can be divided into simplex, half-duplex, and full-duplex:</p><ul><li>There are 6 channels in the direction from CPU1 to CPU2 (P1_TO_P2 sub-channels, P1 represents CPU1, P2 represents CPU2)</li><li>There are 6 channels in the direction from CPU2 to CPU1 (P2_TO_P1 sub-channels, P1 represents CPU1, P2 represents CPU2)</li></ul><p>As shown in the table below, in the ST official IPCC communication model, these 6 channels are used as different software frameworks, where:</p><ul><li>Channel 3 is in simplex mode and is used as the RemoteProc framework, through which the main processor can load the firmware of the coprocessor and control the lifecycle of the coprocessor;</li><li>Channel 2 is in full-duplex mode and is used as the RPMsg framework to transmit messages from A7 to M4;</li><li>Channel 1 is in full-duplex mode and is used as the RPMsg framework to transmit messages from M4 to A7.</li></ul><div class="table-wrap"><table><thead><tr><th><strong>Channel</strong></th><th><strong>Mode</strong></th><th><strong>Usage</strong></th><th><strong>Software client framework: Cortex-A7 (non-secure)</strong></th><th><strong>Software client framework: Cortex-M4</strong></th></tr></thead><tbody><tr><td>Channel 1</td><td>Full-duplex</td><td>RPMsg transfer from Cortex-M4 to Cortex-A7:<br />1. Cortex-M4 uses this channel to indicate a message is available<br />2. Cortex-A7 uses this channel to indicate the message has been processed</td><td>RPMsg framework</td><td>OpenAMP</td></tr><tr><td>Channel 2</td><td>Full duplex</td><td>RPMsg transfer from Cortex-A7 to Cortex-M4:<br />1. Cortex-A7 uses this channel to indicate a message is available<br />2. Cortex-M4 uses this channel to indicate the message has been processed</td><td>RPMsg framework</td><td>OpenAMP</td></tr><tr><td>Channel 3</td><td>Simplex</td><td>Cortex-M4 shutdown request</td><td>RemoteProc framework</td><td>CprocSync cube utility</td></tr><tr><td>Channels 4/5/6</td><td></td><td>Unused</td><td></td><td></td></tr></tbody></table></div><blockquote><p><strong>Simplex Communication</strong>: Refers to signal transmission in only one direction, capable only of sending or receiving</p><p><strong>Half-Duplex Communication</strong>: Signals can be transmitted in both directions, but only sending or receiving is allowed at any given moment (single bus and I2C are both half-duplex communication)</p><p><strong>Full-Duplex Communication</strong>: Full-duplex communication means data is transmitted in both directions simultaneously</p></blockquote><p>It can be seen that in the framework configured by ST:</p><ol><li>The RemoteProc software framework solves the lifecycle issue of remote processors</li><li>The RPMsg software framework solves the inter-core communication problem</li></ol><p>These two are the concerns in multi-core processor communication!</p><p>Under the Linux kernel, ST has already ported the RemoteProc and RPMsg software frameworks. The OpenAMP library used by M4 also has corresponding RemoteProc and RPMsg software frameworks. M4 mainly relies on the existing software framework in the OpenAMP library to communicate with A7.</p><blockquote><p>Note: To facilitate the main core in controlling the coprocessor, the OpenAMP framework was designed on the Linux side. However, to be compatible with the Linux-side OpenAMP framework, M4-related manufacturers also designed an OpenAMP framework. The two are interoperable, but there are still some differences, though they share the same name.</p></blockquote><p>The A7 and M4 of STM32MP157 actually transmit data through Channel 1 and Channel 2:</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607020/cortex-a7-cortex-m4-data-transfer.png" alt="Data transmission between Cortex-A7 and Cortex-M4"><figcaption>Data transmission between Cortex-A7 and Cortex-M4</figcaption></figure></p><h2 id="IPCC-Register">IPCC Register</h2><p>There are 8 registers related to IPCC. The register area is divided into two regions, each occupied by one processor to prevent read-write access conflicts. As shown in the table below, the first 4 registers are occupied by Processor 1, and the last 4 registers are occupied by Processor 2.</p><p>IPCC provides dedicated interrupts for processors. Each processor has its own status mask register bits and set or clear register bits for each channel.</p><div class="table-wrap"><table><thead><tr><th><strong>Register</strong></th><th><strong>Description</strong></th><th><strong>Bit (n indicates 1~6)</strong></th></tr></thead><tbody><tr><td>IPCC_C1CR</td><td>Enable/Disable    Processor 1 TX channel idle interrupt/RX channel occupied interrupt</td><td>TXFIE、RXOIE</td></tr><tr><td>IPCC_C1MR</td><td>Mask/Unmask  Processor 1 TX channel X idle interrupt/RX channel X occupied interrupt</td><td>CHnFM、CHnOM</td></tr><tr><td>IPCC_C1SCR</td><td>Processor 1 TX/RX   Channel X status bit  Set/Clear</td><td>CHnS、CHnC</td></tr><tr><td>IPCC_C1TOC2SR</td><td>Channel occupied/idle</td><td>CHnF</td></tr><tr><td>IPCC_C2CR</td><td>Enable/Disable    Processor 2 TX channel idle interrupt/RX channel occupied interrupt</td><td>TXFIE、RXOIE</td></tr><tr><td>IPCC_C2MR</td><td>Mask/Unmask  Processor 2 TX channel X idle interrupt/RX channel X occupied interrupt</td><td>CHnFM、CHnOM</td></tr><tr><td>IPCC_C2SCR</td><td>Processor 2 TX/RX   Channel X status bit  Set/Clear</td><td>CHnS、CHnC</td></tr><tr><td>IPCC_C2TOC1SR</td><td>Channel occupied/idle</td><td>CHnF</td></tr></tbody></table></div><h3 id="IPCC-C1CR">IPCC_C1CR</h3><p>IPCC Processor 1 Control Register</p><div class="table-wrap"><table><thead><tr><th><strong>31</strong></th><th><strong>30</strong></th><th><strong>29</strong></th><th><strong>28</strong></th><th><strong>27</strong></th><th><strong>26</strong></th><th><strong>25</strong></th><th><strong>24</strong></th><th><strong>23</strong></th><th><strong>22</strong></th><th><strong>21</strong></th><th><strong>20</strong></th><th><strong>19</strong></th><th><strong>18</strong></th><th><strong>17</strong></th><th><strong>16</strong></th></tr></thead><tbody><tr><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td><strong>TXFIE</strong></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>rw</td></tr></tbody></table></div><div class="table-wrap"><table><thead><tr><th><strong>15</strong></th><th><strong>14</strong></th><th><strong>13</strong></th><th><strong>12</strong></th><th><strong>11</strong></th><th><strong>10</strong></th><th><strong>9</strong></th><th><strong>8</strong></th><th><strong>7</strong></th><th><strong>6</strong></th><th><strong>5</strong></th><th><strong>4</strong></th><th><strong>3</strong></th><th><strong>2</strong></th><th><strong>1</strong></th><th><strong>0</strong></th></tr></thead><tbody><tr><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td><strong>RXOIE</strong></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>rw</td></tr></tbody></table></div><ul><li>Bits 17~31 and bits 1~15: Reserved bits, must be kept at reset value.</li><li>Bit 16, TXFIE: Processor 1 transmit (TX) channel idle interrupt enable bit, associated with<strong>IPCC_C1TOC2SR</strong>, when this bit is:<ul><li>1: Enables processor 1 transmit (TX) channel idle interrupt;</li><li>0: Disables processor 1 transmit (TX) channel idle interrupt.</li></ul></li><li>Bit 0, RXOIE: Processor 1 receive (RX) channel occupancy interrupt enable bit, associated with<strong>IPCC_C2TOC1SR</strong>, when this bit is:<ul><li>1: Enables processor 1 receive (RX) channel occupancy interrupt;</li><li>0: Disables processor 1 receive (RX) channel occupancy interrupt.</li></ul></li></ul><h3 id="IPCC-C1MR">IPCC_C1MR</h3><p>IPCC processor 1 mask register</p><div class="table-wrap"><table><thead><tr><th><strong>31</strong></th><th><strong>30</strong></th><th><strong>29</strong></th><th><strong>28</strong></th><th><strong>27</strong></th><th><strong>26</strong></th><th><strong>25</strong></th><th><strong>24</strong></th><th><strong>23</strong></th><th><strong>22</strong></th><th><strong>21</strong></th><th><strong>20</strong></th><th><strong>19</strong></th><th><strong>18</strong></th><th><strong>17</strong></th><th><strong>16</strong></th></tr></thead><tbody><tr><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td><strong>CH6FM</strong></td><td><strong>CH5FM</strong></td><td><strong>CH4FM</strong></td><td><strong>CH3FM</strong></td><td><strong>CH2FM</strong></td><td><strong>CH1FM</strong></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>rw</td><td>rw</td><td>rw</td><td>rw</td><td>rw</td><td>rw</td></tr></tbody></table></div><div class="table-wrap"><table><thead><tr><th><strong>15</strong></th><th><strong>14</strong></th><th><strong>13</strong></th><th><strong>12</strong></th><th><strong>11</strong></th><th><strong>10</strong></th><th><strong>9</strong></th><th><strong>8</strong></th><th><strong>7</strong></th><th><strong>6</strong></th><th><strong>5</strong></th><th><strong>4</strong></th><th><strong>3</strong></th><th><strong>2</strong></th><th><strong>1</strong></th><th><strong>0</strong></th></tr></thead><tbody><tr><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td><strong>CH6OM</strong></td><td><strong>CH5OM</strong></td><td><strong>CH4OM</strong></td><td><strong>CH3OM</strong></td><td><strong>CH2OM</strong></td><td><strong>CH1OM</strong></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>rw</td><td>rw</td><td>rw</td><td>rw</td><td>rw</td><td>rw</td></tr></tbody></table></div><ul><li><p>Bits 22~31 and bits 6~15: Reserved bits, must be kept at reset value.</p></li><li><p>Bits 16<sub>21,**CH1FM**</sub><strong>CH6FM</strong>, processor 1 transmit (TX) channel X idle interrupt mask bit, associated with<strong>IPCC_C1TOC2SR.CHxF</strong>, when this bit is:</p><ul><li>1: Transmit (TX) channel X idle interrupt is masked;</li><li>0: The transmit (TX) channel X idle interrupt is not masked.</li></ul></li><li><p>Bits 0 and 5,<strong>CH1OM</strong> <strong>CH6OM</strong>, the processor 1 receive (RX) channel X occupied interrupt mask bit, associated with<strong>IPCC_C2TOC1SR.CHxF</strong>, when this bit is:</p><ul><li>1: The receive (RX) channel X occupied interrupt is masked;</li><li>0: The receive (RX) channel X occupied interrupt is not masked.</li></ul></li></ul><h3 id="IPCC-C1SCR">IPCC_C1SCR</h3><p>IPCC Processor 1 Status Set Clear Register</p><div class="table-wrap"><table><thead><tr><th><strong>31</strong></th><th><strong>30</strong></th><th><strong>29</strong></th><th><strong>28</strong></th><th><strong>27</strong></th><th><strong>26</strong></th><th><strong>25</strong></th><th><strong>24</strong></th><th><strong>23</strong></th><th><strong>22</strong></th><th><strong>21</strong></th><th><strong>20</strong></th><th><strong>19</strong></th><th><strong>18</strong></th><th><strong>17</strong></th><th><strong>16</strong></th></tr></thead><tbody><tr><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td><strong>CH6FM</strong></td><td><strong>CH5FM</strong></td><td><strong>CH4FM</strong></td><td><strong>CH3FM</strong></td><td><strong>CH2FM</strong></td><td><strong>CH1FM</strong></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>rw</td><td>rw</td><td>rw</td><td>rw</td><td>rw</td><td>rw</td></tr></tbody></table></div><div class="table-wrap"><table><thead><tr><th><strong>15</strong></th><th><strong>14</strong></th><th><strong>13</strong></th><th><strong>12</strong></th><th><strong>11</strong></th><th><strong>10</strong></th><th><strong>9</strong></th><th><strong>8</strong></th><th><strong>7</strong></th><th><strong>6</strong></th><th><strong>5</strong></th><th><strong>4</strong></th><th><strong>3</strong></th><th><strong>2</strong></th><th><strong>1</strong></th><th><strong>0</strong></th></tr></thead><tbody><tr><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td>Res</td><td><strong>CH6OM</strong></td><td><strong>CH5OM</strong></td><td><strong>CH4OM</strong></td><td><strong>CH3OM</strong></td><td><strong>CH2OM</strong></td><td><strong>CH1OM</strong></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td>rw</td><td>rw</td><td>rw</td><td>rw</td><td>rw</td><td>rw</td></tr></tbody></table></div><ul><li>Bits 22 to 31 and bits 6 to 15 are reserved bits and must be kept at their reset value.</li><li>Bits 16 to 21, CH1S to CH6S, processor 1 transmit (TX) channel X status set bits, associated with<strong>IPCC_C1TOC2SR.CHxF</strong>, when this bit is set:<ul><li>1: The processor 1 transmit (TX) channel X status bit is set, i.e., CHnF is set to 1, indicating the channel is occupied;</li><li>0: No action.</li></ul></li><li>Bits 0 to 5, CH1C to CH6C, processor 1 receive (RX) channel X status clear bits, associated with<strong>IPCC_C2TOC1SR.CHxF</strong>, when this bit is set:<ul><li>1: The processor 1 receive (RX) channel X status bit is cleared;</li><li>0: No action</li></ul></li></ul><h2 id="IPCC-function-description">IPCC function description</h2><p>IPCC’s control of processor communication is actually implemented through interrupts, called inter-processor interrupts (IPI). Each processor has two interrupt lines, which are:</p><ul><li>One is used for RX channel occupancy (the sending processor publishes data);</li><li>One is used for TX channel idle (the receiving processor reads communication data).</li></ul><p>Each channel has interrupt masking:</p><ul><li><strong>Channel occupancy mask (bit CHnOM);</strong></li><li><strong>Channel idle mask (bit CHnFM).</strong></li></ul><blockquote><p>In the context of computers, microcontrollers, or hardware peripherals (such as DMA, Mailbox, IPCC and other communication controllers),<strong>“Mask” means to “turn off” or “filter out” a certain interrupt signal, preventing it from being reported to the CPU.</strong>。</p></blockquote><p>Each sub-channel has two working modes:</p><ul><li>Simplex mode (each channel has its own communication data storage location);</li><li>Half-duplex mode (a single channel associated with a bidirectional communication data information storage location).</li></ul><p>The communication data is located in shared memory (note that shared memory is not part of the IPCC). Each communication, the IPCC module provides a<strong>channel status flag bit CHnF</strong>(n can take values 1 to 6, indicating the corresponding channel):</p><ul><li><strong>When CHnF=0, it indicates that the relevant channel is idle.</strong>(It can also be considered that the communication data has been read by the receiving processor, and the channel is now in an idle state),<strong>At this point, the sending processor can occupy this channel to send data;</strong></li><li><strong>When CHnF=1, it indicates that the relevant channel has been occupied.</strong>(i.e., the communication data has been published by the sending processor),<strong>At this point, the receiving processor can access the channel to read the data.</strong></li></ul><p>IPCC provides a non-blocking signaling mechanism for channel management:</p><ul><li>Message availability interrupt;</li><li>Channel flow control (e.g., generating a TX channel idle interrupt is called flow open, and when the channel is occupied, it is called flow close).</li></ul><p>Applications benefit from non-blocking interrupt-based message exchange and channel flow control for inter-core communication, with each sub-channel having a transmission direction:</p><ul><li>Sent from CPU1 and received by CPU2;</li><li>Or sent from CPU2 and received by CPU1.</li></ul><h3 id="Simplex-transmission-mode">Simplex transmission mode</h3><p>The following figure shows a schematic diagram of the IPCC simplex transmission mode.</p><ul><li>When the channel status flag indicates channel occupied (CHnF=1), this is because the receiver has not released the channel from the previous message. At this point, the channel idle interrupt is unmasked, and then the TX idle interrupt is awaited.</li><li>Once the receiver releases the channel, a channel idle interrupt is generated (stream open). When the channel idle interrupt occurs, the channel idle interrupt is masked, and the message can be written to the data buffer. Subsequently, the channel status flag is set to occupied, which triggers the channel occupied interrupt at the receiver.</li></ul><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607020/simplex-transmission.png" alt="Simplex transmission"><figcaption>Simplex transmission</figcaption></figure></p><h3 id="Simplex-reception-mode">Simplex reception mode</h3><p>The following diagram shows the IPCC simplex transmission mode schematic. When a channel occupied interrupt occurs, the receiver determines which channel is occupied and masks the corresponding channel occupied interrupt. Subsequently, data can be read from the shared memory. Once the data is read, the channel status flag CHnF is cleared (CHnF=0), and the channel occupied interrupt is unmasked.</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607020/simplex-reception.png" alt="Simplex reception"><figcaption>Simplex reception</figcaption></figure></p><h3 id="Half-duplex-transmission-mode">Half-duplex transmission mode</h3><p>The following diagram shows the IPCC half-duplex transmission mode schematic.</p><p>The half-duplex process allows using a single shared buffer to transmit a message from the sender to the receiver, and then send a response (response pending) from the receiver back to the sender.</p><p><strong>Sender data transmission process:</strong></p><ul><li>The software variable response pending=1 indicates that the sender is waiting for a response from the receiver.</li><li>response pending=0 indicates that a response from the receiver has been obtained.</li></ul><p>First, the sender checks the channel status flag. If the channel status flag indicates the channel is occupied (CHnF=1), meaning the receiver has not yet sent a response to the previous message, the sender waits for the response. If the channel is idle, the sender can write the message into the shared memory.</p><p>Subsequently, the channel status flag is set to occupied, which triggers the RX channel occupied interrupt at the receiver. Once the channel status flag CHnF=1, the channel idle interrupt is unmasked. The channel idle interrupt indicates whether the response sent by the receiver is available. When the channel idle interrupt occurs (response ready), the sender determines which channel to release and masks the corresponding channel idle interrupt. Then, the response can be read from the shared memory.</p><p><strong>Receiver response process:</strong></p><p>The receiving processor waits for the software variable response pending to be equal to 1. If it is equal to 1, the receiver writes the response into the shared memory (publishes the response). Once the response is published, the channel status flag CHnF is cleared by CHnC, so CHnF becomes 0, and the receiver unmasks the channel occupancy interrupt (CHnOM = 0).</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607020/half-duplex-transmission-mode.png" alt="Half-duplex transmission mode"><figcaption>Half-duplex transmission mode</figcaption></figure></p><h3 id="Half-duplex-reception-mode">Half-duplex reception mode</h3><p>The following figure shows a schematic diagram of the IPCC half-duplex reception mode.</p><ul><li>Receiver reads data: When a channel occupancy interrupt occurs, the receiver determines which channel is occupied and masks the corresponding channel occupancy interrupt, then receives data from the shared memory. The channel is released only after the receiver sends the response to the shared memory.</li><li>Sender reads response: To receive the response, the channel idle interrupt is unmasked. The sending processor checks which channel becomes idle, masks the relevant channel idle interrupt, and then reads the response from the shared memory.</li></ul><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607020/ipcc-half-duplex-reception.png" alt="IPCC half-duplex reception"><figcaption>IPCC half-duplex reception</figcaption></figure></p><p>IPCC provides a non-blocking signaling mechanism for 6 bidirectional channels to atomically publish and retrieve communication data. The non-blocking method allows processors to exchange information in a non-blocking manner, such as reading data. When conditions are not met and results cannot be obtained immediately, the process is suspended, and then periodically checked to see if conditions are met. If met, a read operation is performed; if not, no read is performed. This is the non-blocking method.</p><p>The communication process described above can be represented by the following figure. All communicating processors can access the shared memory. Around the shared memory, an interrupt line can be configured from the main processor to the coprocessor and from the coprocessor to the main processor, i.e.,<strong>Inter-processor interrupt (PPI, referred to as core interrupt)</strong>, the initiator of the core interrupt first writes the message data to the shared memory, then initiates the inter-processor interrupt. The interrupted core thread reads the shared memory in the interrupt service routine to obtain the data notified by the initiator.</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607020/shared-memory-inter-core-interrupt.png" alt="Shared memory and inter-processor interrupt"><figcaption>Shared memory and inter-processor interrupt</figcaption></figure></p><h2 id="Mailbox-framework">Mailbox framework</h2><p>The Mailbox framework is closely related to IPCC. Mailbox is a driver architecture that relies on the hardware platform for implementation. For example, the Mailbox on the STM32MP157 platform depends on the IPCC peripheral. Its Mailbox framework is shown in the following figure: (Mailbox is a tool for message transmission, relying on IPCC at the bottom layer, but IPCC does not transmit data. Mailbox, based on IPCC, can transmit message data.)</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/202607020/mailbox-framework.png" alt="Mailbox framework"><figcaption>Mailbox framework</figcaption></figure></p><p>How does the upper-layer application know that data has been completely sent or received? This task is handled by the Mailbox framework. The implementation of Mailbox is divided into the Mailbox controller and the Mailbox client:</p><ul><li><p>The mailbox controller is mainly responsible for configuring and handling message queues or interrupt requests (IRQ) from the IPCC peripheral, and provides a common API for mailbox clients responsible for sending or receiving notification messages.</p></li><li><p>The mailbox client is mainly responsible for sending or receiving notification messages. It sends or receives notification messages through the channel provided by the mailbox controller, which is the IPCC channel.</p></li></ul><p>Users can define their own mailbox client. As shown in the figure above, the mailbox controller under Linux is<code>stm32_ipcc</code>, which configures and controls the IPCC peripheral and can provide mailbox services.<code>stm32_rproc</code>is the remote processor platform driver. It mainly handles platform resources associated with the remote processor (such as registers, watchdog, reset, clock, and memory), can register corresponding callback functions into the Remoteproc framework, and can also forward notification messages to the remote processor through the mailbox framework.</p><p>The general workflow of the mailbox framework is:</p><ol><li>First, register the mailbox controller;</li><li>Before the mailbox client sends data, it first requests a channel;</li><li>The client sends data;</li><li>The mailbox client records the data;</li><li>The mailbox controller calls back the data received from the lower layer to the upper-layer application;</li><li>When data transmission is complete, the mailbox controller notifies the upper layer that the current data has been sent;</li><li>The mailbox client releases the channel;</li></ol><p>Regarding the Mailbox framework, in the Linux kernel source code<code>drivers/mailbox</code>There are related drivers under the directory.</p><h2 id="References">References</h2><div class="reference-source"><span class="hidden-anchor" id="referfrom_[1]"></span><a class="reference-anchor" href="#referto_[1]">[1]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="【STM32MP157 Heterogeneous Communication Framework Learning】（2）IPCCCommunication Framework" href=" https://blog.csdn.net/qq_54050349/article/details/154745995">【STM32MP157 Heterogeneous Communication Framework Learning】（2）IPCCCommunication Framework</a></div>]]></content>
    
    
    <summary type="html">This article introduces the working principle of the IPCC (Inter-Processor Communication Controller) hardware module in the STM32MP157, discusses its process of achieving signal notification between the Cortex-A7 and Cortex-M4 cores through shared memory and hardware interrupt mechanisms, and summarizes the channel allocation, software framework application, and related register configuration of the IPCC.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>Rpmsg Char Driver</title>
    <link href="https://even629.com/en/posts/202606290/"/>
    <id>https://even629.com/en/posts/202606290/</id>
    <published>2026-06-29T14:00:13.000Z</published>
    <updated>2026-06-29T14:00:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-06-29</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the implementation mechanism of the Rpmsg Char Driver character device driver based on Linux 5.10.x. It discusses in detail the classic architecture design where the control device and endpoint device are separated, and summarizes the specific processes and key code logic of driver registration, delayed endpoint creation, lock and wait queue synchronization mechanisms, as well as user-space message sending and receiving.</blockquote><hr><blockquote><p>Current code analysis is based on Linux 5.10.x</p></blockquote><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/shared/05.png" alt="rpmsg.drawio"><figcaption>rpmsg.drawio</figcaption></figure></p><p><code>rpmsg_char.c</code>implements<code>rpmsg_driver</code>and registers it on the Rpmsg Bus, implementing an interface for user-space interaction, undertaking<code>virtio_rpmsg_bus.c</code>to register<code>rpmsg_device</code></p><h1 id="module-init-module-exit">module_init / module_exit</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_DEV_MAX(MINORMASK + 1)</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">dev_t</span> rpmsg_major;</span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="keyword">class</span> *<span class="title">rpmsg_class</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_char_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">ret = alloc_chrdev_region(&amp;rpmsg_major, <span class="number">0</span>, RPMSG_DEV_MAX, <span class="string">&quot;rpmsg&quot;</span>);</span><br><span class="line"><span class="keyword">if</span> (ret &lt; <span class="number">0</span>) &#123;</span><br><span class="line">pr_err(<span class="string">&quot;rpmsg: failed to allocate char dev region\n&quot;</span>);</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">rpmsg_class = class_create(THIS_MODULE, <span class="string">&quot;rpmsg&quot;</span>);</span><br><span class="line"><span class="keyword">if</span> (IS_ERR(rpmsg_class)) &#123;</span><br><span class="line">pr_err(<span class="string">&quot;failed to create rpmsg class\n&quot;</span>);</span><br><span class="line">unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);</span><br><span class="line"><span class="keyword">return</span> PTR_ERR(rpmsg_class);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">ret = register_rpmsg_driver(&amp;rpmsg_chrdev_driver);</span><br><span class="line"><span class="keyword">if</span> (ret &lt; <span class="number">0</span>) &#123;</span><br><span class="line">pr_err(<span class="string">&quot;rpmsgchr: failed to register rpmsg driver\n&quot;</span>);</span><br><span class="line">class_destroy(rpmsg_class);</span><br><span class="line">unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line">postcore_initcall(rpmsg_char_init);</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">rpmsg_chrdev_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">unregister_rpmsg_driver(&amp;rpmsg_chrdev_driver);</span><br><span class="line">class_destroy(rpmsg_class);</span><br><span class="line">unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);</span><br><span class="line">&#125;</span><br><span class="line">module_exit(rpmsg_chrdev_exit);</span><br><span class="line"></span><br><span class="line">MODULE_ALIAS(<span class="string">&quot;rpmsg:rpmsg_chrdev&quot;</span>);</span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL v2&quot;</span>);</span><br></pre></td></tr></table></figure><p><code>rpmsg_char.c</code>is a character device driver with the following hierarchy:</p><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/Linux/OpenAMP/rpmsg/202606290/rpmsg_char-drawio.png" alt="rpmsg_char.drawio"><figcaption>rpmsg_char.drawio</figcaption></figure></p><p>Note that it uses<code>postcore_initcall</code>, which is earlier than<code>module_init</code>earlier, because<code> rpmsg_core.c</code>’s bus also uses<code>postcore_initcall</code>, both are registered after the driver model is ready.</p><p><code>rpmsg_char_init</code>does three things:</p><ol><li><code>alloc_chrdev_region(&amp;rpmsg_major, 0, RPMSG_DEV_MAX, &quot;rpmsg&quot;) </code>—— Dynamically allocate a major device number,<code>RPMSG_DEV_MAX = MINORMASK+1</code>(i.e., the entire minor device number space).</li><li><code>class_create(THIS_MODULE, &quot;rpmsg&quot;)</code>—— Create<code>/sys/class/rpmsg</code>, so that<code>cdev_device_add</code>will automatically generate device nodes under<code>/dev/</code>(depending on<code>udev</code>/<code>devtmpfs</code>）。</li><li><code>register_rpmsg_driver(&amp;rpmsg_chrdev_driver)</code>—— Register an rpmsg driver (not a platform driver! It is a driver attached to the rpmsg bus).</li></ol><p>And<code>rpmsg_chrdev_driver</code>is as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_driver</span> <span class="title">rpmsg_chrdev_driver</span> =</span> &#123;</span><br><span class="line">.probe = rpmsg_chrdev_probe,</span><br><span class="line">.remove = rpmsg_chrdev_remove,</span><br><span class="line">.drv = &#123;</span><br><span class="line">.name = <span class="string">&quot;rpmsg_chrdev&quot;</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="Key-Data-Structures">Key Data Structures</h1><div class="table-wrap"><table><thead><tr><th style="text-align:left">Type</th><th style="text-align:left">Device Node</th><th style="text-align:left">struct</th><th style="text-align:left">Created By</th><th style="text-align:left">Purpose</th></tr></thead><tbody><tr><td style="text-align:left"><strong>Control Device</strong></td><td style="text-align:left"><code>/dev/rpmsg_ctrl0</code></td><td style="text-align:left"><code>rpmsg_ctrldev</code></td><td style="text-align:left"><code>rpmsg_chrdev_probe</code></td><td style="text-align:left">One per channel; users “create endpoints” on it via ioctl</td></tr><tr><td style="text-align:left"><strong>Endpoint device</strong></td><td style="text-align:left"><code>/dev/rpmsg0</code></td><td style="text-align:left"><code>rpmsg_eptdev</code></td><td style="text-align:left"><code>rpmsg_ctrldev_ioctl(CREATE)</code></td><td style="text-align:left">One per endpoint; users read/write/poll it to send and receive messages</td></tr></tbody></table></div><p>This separation of “control device + data device” is a classic pattern in Linux:<strong>The control node is used to instantiate the data node, and the data node carries the actual I/O</strong>。</p><h2 id="struct-rpmsg-ctrldev">struct rpmsg_ctrldev</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_ctrldev - control device for instantiating endpoint devices</span></span><br><span class="line"><span class="comment"> * @rpdev:underlaying rpmsg device</span></span><br><span class="line"><span class="comment"> * @cdev:cdev for the ctrl device</span></span><br><span class="line"><span class="comment"> * @dev:device for the ctrl device</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ctrldev</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>;</span>   <span class="comment">// Underlying rpmsg channel device</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span>              <span class="comment">// Character device</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> <span class="title">dev</span>;</span>             <span class="comment">// Embedded device, attached under rpmsg_class</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="struct-rpmsg-eptdev">struct rpmsg_eptdev</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_eptdev - endpoint device context</span></span><br><span class="line"><span class="comment"> * @dev:endpoint device</span></span><br><span class="line"><span class="comment"> * @cdev:cdev for the endpoint device</span></span><br><span class="line"><span class="comment"> * @rpdev:underlaying rpmsg device</span></span><br><span class="line"><span class="comment"> * @chinfo:info used to open the endpoint</span></span><br><span class="line"><span class="comment"> * @ept_lock:synchronization of @ept modifications</span></span><br><span class="line"><span class="comment"> * @ept:rpmsg endpoint reference, when open</span></span><br><span class="line"><span class="comment"> * @queue_lock:synchronization of @queue operations</span></span><br><span class="line"><span class="comment"> * @queue:incoming message queue</span></span><br><span class="line"><span class="comment"> * @readq:wait object for incoming queue</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> <span class="title">dev</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">cdev</span> <span class="title">cdev</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>;</span>          <span class="comment">// Underlying channel</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span>;</span>    <span class="comment">// Channel information (name/src/dst) used when opening</span></span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">ept_lock</span>;</span>               <span class="comment">// Protect modifications to the ept pointer</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept</span>;</span>          <span class="comment">// Real endpoint created only when opened, can be NULL</span></span><br><span class="line"></span><br><span class="line">    <span class="type">spinlock_t</span> queue_lock;               <span class="comment">// Protect the receive queue</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sk_buff_head</span> <span class="title">queue</span>;</span>           <span class="comment">// Receive message queue (one skb per message)</span></span><br><span class="line">    <span class="type">wait_queue_head_t</span> readq;             <span class="comment">// Wait queue for blocking reads</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Lock and wait queue:</p><ul><li><code>struct mutex ept_lock;</code>: Protects the ept pointer. The ept becomes NULL in three cases:<code>release</code>、<code>destroy ioctl</code>, parent device<code>remove</code>. The read/write path must first acquire this lock to confirm the ept is still alive.</li><li><code> spinlock_t queue_lock;</code>: Protects the queue (skb linked list). The callback<code>rpmsg_ept_cb</code>enqueues in interrupt/atomic context, while read_iter dequeues in process context, so a spinlock is used here, and in the callback<code>spin_lock</code>, in read<code>spin_lock_irqsave</code>。</li><li><code>wait_queue_head_t readq;</code>：<code>rpmsg_ept_cb</code>after enqueuing<code>wake_up_interruptible</code>，<code>read_iter</code>when the queue is empty<code>wait_event_interruptible</code>. This is a typical “producer-consumer + wait queue” pattern.</li></ul><h1 id="rpmsg-driver">rpmsg_driver</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_driver</span> <span class="title">rpmsg_chrdev_driver</span> =</span> &#123;</span><br><span class="line">.probe = rpmsg_chrdev_probe,</span><br><span class="line">.remove = rpmsg_chrdev_remove,</span><br><span class="line">.drv = &#123;</span><br><span class="line">.name = <span class="string">&quot;rpmsg_chrdev&quot;</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Note: No callback function is defined here</p><h2 id="rpmsg-chrdev-probe">rpmsg_chrdev_probe()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_DEV_MAX(MINORMASK + 1)</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">dev_t</span> rpmsg_major;</span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="keyword">class</span> *<span class="title">rpmsg_class</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="title function_">DEFINE_IDA</span><span class="params">(rpmsg_ctrl_ida)</span>;</span><br><span class="line"><span class="type">static</span> <span class="title function_">DEFINE_IDA</span><span class="params">(rpmsg_ept_ida)</span>;</span><br><span class="line"><span class="type">static</span> <span class="title function_">DEFINE_IDA</span><span class="params">(rpmsg_minor_ida)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_chrdev_probe</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ctrldev</span> *<span class="title">ctrldev</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span>;</span></span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">ctrldev = kzalloc(<span class="keyword">sizeof</span>(*ctrldev), GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (!ctrldev)</span><br><span class="line"><span class="keyword">return</span> -ENOMEM;</span><br><span class="line"></span><br><span class="line">ctrldev-&gt;rpdev = rpdev;</span><br><span class="line"></span><br><span class="line">dev = &amp;ctrldev-&gt;dev;</span><br><span class="line">device_initialize(dev);</span><br><span class="line">dev-&gt;parent = &amp;rpdev-&gt;dev;</span><br><span class="line">dev-&gt;<span class="class"><span class="keyword">class</span> =</span> rpmsg_class;</span><br><span class="line"></span><br><span class="line">cdev_init(&amp;ctrldev-&gt;cdev, &amp;rpmsg_ctrldev_fops);</span><br><span class="line">ctrldev-&gt;cdev.owner = THIS_MODULE;</span><br><span class="line"></span><br><span class="line">ret = ida_simple_get(&amp;rpmsg_minor_ida, <span class="number">0</span>, RPMSG_DEV_MAX, GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line"><span class="keyword">goto</span> free_ctrldev;</span><br><span class="line">dev-&gt;devt = MKDEV(MAJOR(rpmsg_major), ret);</span><br><span class="line"></span><br><span class="line">ret = ida_simple_get(&amp;rpmsg_ctrl_ida, <span class="number">0</span>, <span class="number">0</span>, GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line"><span class="keyword">goto</span> free_minor_ida;</span><br><span class="line">dev-&gt;id = ret;</span><br><span class="line">dev_set_name(&amp;ctrldev-&gt;dev, <span class="string">&quot;rpmsg_ctrl%d&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line">ret = cdev_device_add(&amp;ctrldev-&gt;cdev, &amp;ctrldev-&gt;dev);</span><br><span class="line"><span class="keyword">if</span> (ret)</span><br><span class="line"><span class="keyword">goto</span> free_ctrl_ida;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* We can now rely on the release function for cleanup */</span></span><br><span class="line">dev-&gt;release = rpmsg_ctrldev_release_device;</span><br><span class="line"></span><br><span class="line">dev_set_drvdata(&amp;rpdev-&gt;dev, ctrldev);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">free_ctrl_ida:</span><br><span class="line">ida_simple_remove(&amp;rpmsg_ctrl_ida, dev-&gt;id);</span><br><span class="line">free_minor_ida:</span><br><span class="line">ida_simple_remove(&amp;rpmsg_minor_ida, MINOR(dev-&gt;devt));</span><br><span class="line">free_ctrldev:</span><br><span class="line">put_device(dev);</span><br><span class="line">kfree(ctrldev);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>When the rpmsg bus matches a<code>rpmsg_device</code>to<code>rpmsg_chrdev_driver</code>, it is called<code>rpmsg_chrdev_probe</code>. Flow:</p><ol><li>kzalloc a ctrldev,<code>ctrldev-&gt;rpdev = rpdev</code>。</li><li><code>device_initialize</code>+ set<code>parent</code>/<code>class</code>，<code>cdev_init(&amp;ctrldev-&gt;cdev, &amp;rpmsg_ctrldev_fops)</code>。</li><li>twice<code>ida_simple_get</code>: from<code>rpmsg_minor_ida</code>get the minor device number, from<code>rpmsg_ctrl_ida</code>get the id (used for<code>rpmsg_ctrl%d</code>）。</li><li><code>cdev_device_add</code>— register cdev and device together,<code>/dev/rpmsg_ctrlN</code>appears.</li><li>Key point:<code>dev-&gt;release = rpmsg_ctrldev_release_device</code>is assigned after<code>cdev_device_add</code>. The comment says “We can now rely on the release function for cleanup” — meaning<code>cdev_device_add</code>If it fails before success, it goes through the manual error label to release; after success, it is handed over to the device model’s release callback for cleanup (kfree when the last reference reaches zero). This is a very standard refcount + release pattern in the Linux device model.</li><li><code>dev_set_drvdata(&amp;rpdev-&gt;dev, ctrldev)</code>— so that during remove, ctrldev can be retrieved from rpdev.</li></ol><h2 id="rpmsg-chrdev-remove">rpmsg_chrdev_remove()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">rpmsg_chrdev_remove</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ctrldev</span> *<span class="title">ctrldev</span> =</span> dev_get_drvdata(&amp;rpdev-&gt;dev);</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Destroy all endpoints */</span></span><br><span class="line">ret = device_for_each_child(&amp;ctrldev-&gt;dev, <span class="literal">NULL</span>, rpmsg_eptdev_destroy);</span><br><span class="line"><span class="keyword">if</span> (ret)</span><br><span class="line">dev_warn(&amp;rpdev-&gt;dev, <span class="string">&quot;failed to nuke endpoints: %d\n&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line">cdev_device_del(&amp;ctrldev-&gt;cdev, &amp;ctrldev-&gt;dev);</span><br><span class="line">put_device(&amp;ctrldev-&gt;dev);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="rpmsg-ctrldev-control-node">rpmsg_ctrldev control node</h1><h2 id="file-operations">file_operations</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">rpmsg_ctrldev_fops</span> =</span> &#123;</span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.open = rpmsg_ctrldev_open,</span><br><span class="line">.release = rpmsg_ctrldev_release,</span><br><span class="line">.unlocked_ioctl = rpmsg_ctrldev_ioctl,</span><br><span class="line">.compat_ioctl = compat_ptr_ioctl,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="rpmsg-ctrldev-open">rpmsg_ctrldev_open()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_ctrldev_open</span><span class="params">(<span class="keyword">struct</span> inode *inode, <span class="keyword">struct</span> file *filp)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ctrldev</span> *<span class="title">ctrldev</span> =</span> cdev_to_ctrldev(inode-&gt;i_cdev);</span><br><span class="line"></span><br><span class="line">get_device(&amp;ctrldev-&gt;dev);</span><br><span class="line">filp-&gt;private_data = ctrldev;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="rpmsg-ctrldev-release">rpmsg_ctrldev_release()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_ctrldev_release</span><span class="params">(<span class="keyword">struct</span> inode *inode, <span class="keyword">struct</span> file *filp)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ctrldev</span> *<span class="title">ctrldev</span> =</span> cdev_to_ctrldev(inode-&gt;i_cdev);</span><br><span class="line"></span><br><span class="line">put_device(&amp;ctrldev-&gt;dev);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In the probe function, there is<code>dev-&gt;release = rpmsg_ctrldev_release_device;</code>, so the actual<code>release</code>The function is</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">rpmsg_ctrldev_release_device</span><span class="params">(<span class="keyword">struct</span> device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ctrldev</span> *<span class="title">ctrldev</span> =</span> dev_to_ctrldev(dev);</span><br><span class="line"></span><br><span class="line">ida_simple_remove(&amp;rpmsg_ctrl_ida, dev-&gt;id);</span><br><span class="line">ida_simple_remove(&amp;rpmsg_minor_ida, MINOR(dev-&gt;devt));</span><br><span class="line">kfree(ctrldev);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="rpmsg-ctrldev-ioctl">rpmsg_ctrldev_ioctl()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">long</span> <span class="title function_">rpmsg_ctrldev_ioctl</span><span class="params">(<span class="keyword">struct</span> file *fp, <span class="type">unsigned</span> <span class="type">int</span> cmd,</span></span><br><span class="line"><span class="params"><span class="type">unsigned</span> <span class="type">long</span> arg)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ctrldev</span> *<span class="title">ctrldev</span> =</span> fp-&gt;private_data;</span><br><span class="line"><span class="type">void</span> __user *argp = (<span class="type">void</span> __user *)arg;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint_info</span> <span class="title">eptinfo</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (cmd != RPMSG_CREATE_EPT_IOCTL)</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (copy_from_user(&amp;eptinfo, argp, <span class="keyword">sizeof</span>(eptinfo)))</span><br><span class="line"><span class="keyword">return</span> -EFAULT;</span><br><span class="line"></span><br><span class="line"><span class="built_in">memcpy</span>(chinfo.name, eptinfo.name, RPMSG_NAME_SIZE);</span><br><span class="line">chinfo.name[RPMSG_NAME_SIZE<span class="number">-1</span>] = <span class="string">&#x27;\0&#x27;</span>;</span><br><span class="line">chinfo.src = eptinfo.src;</span><br><span class="line">chinfo.dst = eptinfo.dst;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> rpmsg_eptdev_create(ctrldev, chinfo);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Use this function to create ept, call<code>rpmsg_eptdev_create()</code></p><h3 id="rpmsg-eptdev-create">rpmsg_eptdev_create()</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_eptdev_create</span><span class="params">(<span class="keyword">struct</span> rpmsg_ctrldev *ctrldev,</span></span><br><span class="line"><span class="params">       <span class="keyword">struct</span> rpmsg_channel_info chinfo)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> ctrldev-&gt;rpdev;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span>;</span></span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">eptdev = kzalloc(<span class="keyword">sizeof</span>(*eptdev), GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (!eptdev)</span><br><span class="line"><span class="keyword">return</span> -ENOMEM;</span><br><span class="line"></span><br><span class="line">dev = &amp;eptdev-&gt;dev;</span><br><span class="line">eptdev-&gt;rpdev = rpdev;</span><br><span class="line">eptdev-&gt;chinfo = chinfo;</span><br><span class="line"></span><br><span class="line">mutex_init(&amp;eptdev-&gt;ept_lock);</span><br><span class="line">spin_lock_init(&amp;eptdev-&gt;queue_lock);</span><br><span class="line">skb_queue_head_init(&amp;eptdev-&gt;<span class="built_in">queue</span>);</span><br><span class="line">init_waitqueue_head(&amp;eptdev-&gt;readq);</span><br><span class="line"></span><br><span class="line">device_initialize(dev);</span><br><span class="line">dev-&gt;<span class="class"><span class="keyword">class</span> =</span> rpmsg_class;</span><br><span class="line">dev-&gt;parent = &amp;ctrldev-&gt;dev;</span><br><span class="line">dev-&gt;groups = rpmsg_eptdev_groups;</span><br><span class="line">dev_set_drvdata(dev, eptdev);</span><br><span class="line"></span><br><span class="line">cdev_init(&amp;eptdev-&gt;cdev, &amp;rpmsg_eptdev_fops);</span><br><span class="line">eptdev-&gt;cdev.owner = THIS_MODULE;</span><br><span class="line"></span><br><span class="line">ret = ida_simple_get(&amp;rpmsg_minor_ida, <span class="number">0</span>, RPMSG_DEV_MAX, GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line"><span class="keyword">goto</span> free_eptdev;</span><br><span class="line">dev-&gt;devt = MKDEV(MAJOR(rpmsg_major), ret);</span><br><span class="line"></span><br><span class="line">ret = ida_simple_get(&amp;rpmsg_ept_ida, <span class="number">0</span>, <span class="number">0</span>, GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (ret &lt; <span class="number">0</span>)</span><br><span class="line"><span class="keyword">goto</span> free_minor_ida;</span><br><span class="line">dev-&gt;id = ret;</span><br><span class="line">dev_set_name(dev, <span class="string">&quot;rpmsg%d&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line">ret = cdev_device_add(&amp;eptdev-&gt;cdev, &amp;eptdev-&gt;dev);</span><br><span class="line"><span class="keyword">if</span> (ret)</span><br><span class="line"><span class="keyword">goto</span> free_ept_ida;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* We can now rely on the release function for cleanup */</span></span><br><span class="line">dev-&gt;release = rpmsg_eptdev_release_device;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">free_ept_ida:</span><br><span class="line">ida_simple_remove(&amp;rpmsg_ept_ida, dev-&gt;id);</span><br><span class="line">free_minor_ida:</span><br><span class="line">ida_simple_remove(&amp;rpmsg_minor_ida, MINOR(dev-&gt;devt));</span><br><span class="line">free_eptdev:</span><br><span class="line">put_device(dev);</span><br><span class="line">kfree(eptdev);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li>kzalloc eptdev, fill in rpdev, chinfo.</li><li>Initialize locks, skb queue, wait queue head.</li><li>device_initialize + set<code>class/parent/groups/drvdata</code>。<code>groups = rpmsg_eptdev_groups</code>Provide name/src/dst read-only attributes to sysfs</li><li>cdev_init with<code>rpmsg_eptdev_fops</code>。</li><li>Two ida_simple_get to obtain minor and ept id,<code>dev_set_name(dev, &quot;rpmsg%d&quot;, ret) </code>→ <code>/dev/rpmsgN</code>。</li><li>cdev_device_add, after success set dev-&gt;release.</li><li>Note: at this point<code>eptdev-&gt;ept == NULL</code>! The actual endpoint has not been created yet.<strong>The endpoint is created only at open. This is lazy creation to avoid occupying addresses without use.</strong></li></ol><p>The goto order in the error handling path is strictly opposite to the resource acquisition order, following the standard unwind style. Note free_put in eptdev_After device, then kfree—there is actually a detail here:<code>device_initialize</code>After that, should use put_device lets the release callback free it, but because release is set in cdev_device_only after add succeeds, and it hasn’t been set in this path, so put_device won’t actually kfree, manual kfree is needed. This is exactly the cost of delayed assignment of release.</p><h2 id="compat-ptr-ioctl">compat_ptr_ioctl()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifdef</span> CONFIG_COMPAT</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * compat_ptr_ioctl - generic implementation of .compat_ioctl file operation</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This is not normally called as a function, but instead set in struct</span></span><br><span class="line"><span class="comment"> * file_operations as</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *     .compat_ioctl = compat_ptr_ioctl,</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * On most architectures, the compat_ptr_ioctl() just passes all arguments</span></span><br><span class="line"><span class="comment"> * to the corresponding -&gt;ioctl handler. The exception is arch/s390, where</span></span><br><span class="line"><span class="comment"> * compat_ptr() clears the top bit of a 32-bit pointer value, so user space</span></span><br><span class="line"><span class="comment"> * pointers to the second 2GB alias the first 2GB, as is the case for</span></span><br><span class="line"><span class="comment"> * native 32-bit s390 user space.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * The compat_ptr_ioctl() function must therefore be used only with ioctl</span></span><br><span class="line"><span class="comment"> * functions that either ignore the argument or pass a pointer to a</span></span><br><span class="line"><span class="comment"> * compatible data type.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If any ioctl command handled by fops-&gt;unlocked_ioctl passes a plain</span></span><br><span class="line"><span class="comment"> * integer instead of a pointer, or any of the passed data types</span></span><br><span class="line"><span class="comment"> * is incompatible between 32-bit and 64-bit architectures, a proper</span></span><br><span class="line"><span class="comment"> * handler is required instead of compat_ptr_ioctl.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">long</span> <span class="title function_">compat_ptr_ioctl</span><span class="params">(<span class="keyword">struct</span> file *file, <span class="type">unsigned</span> <span class="type">int</span> cmd, <span class="type">unsigned</span> <span class="type">long</span> arg)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (!file-&gt;f_op-&gt;unlocked_ioctl)</span><br><span class="line"><span class="keyword">return</span> -ENOIOCTLCMD;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> file-&gt;f_op-&gt;unlocked_ioctl(file, cmd, (<span class="type">unsigned</span> <span class="type">long</span>)compat_ptr(arg));</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(compat_ptr_ioctl);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>Directly use<code>fs/ioctl.c</code>in<code>compat_ptr_ioctl</code>implementation, 64-bit kernel compatible with 32-bit userspace</p><h1 id="rpmsg-eptdev-ept-node">rpmsg_eptdev ept node</h1><h2 id="file-operations-2">file_operations</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">file_operations</span> <span class="title">rpmsg_eptdev_fops</span> =</span> &#123;</span><br><span class="line">.owner = THIS_MODULE,</span><br><span class="line">.open = rpmsg_eptdev_open,</span><br><span class="line">.release = rpmsg_eptdev_release,</span><br><span class="line">.read_iter = rpmsg_eptdev_read_iter,</span><br><span class="line">.write_iter = rpmsg_eptdev_write_iter,</span><br><span class="line">.poll = rpmsg_eptdev_poll,</span><br><span class="line">.unlocked_ioctl = rpmsg_eptdev_ioctl,</span><br><span class="line">.compat_ioctl = compat_ptr_ioctl,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="rpmsg-eptdev-open">rpmsg_eptdev_open()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_eptdev_open</span><span class="params">(<span class="keyword">struct</span> inode *inode, <span class="keyword">struct</span> file *filp)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span> =</span> cdev_to_eptdev(inode-&gt;i_cdev);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> eptdev-&gt;rpdev;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span> =</span> &amp;eptdev-&gt;dev;</span><br><span class="line"></span><br><span class="line">get_device(dev);</span><br><span class="line"></span><br><span class="line">ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev-&gt;chinfo);</span><br><span class="line"><span class="keyword">if</span> (!ept) &#123;</span><br><span class="line">dev_err(dev, <span class="string">&quot;failed to open %s\n&quot;</span>, eptdev-&gt;chinfo.name);</span><br><span class="line">put_device(dev);</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">eptdev-&gt;ept = ept;</span><br><span class="line">filp-&gt;private_data = eptdev;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><code>rpmsg_create_ept</code>forwarded to core and then to the virtio backend’s<code>virtio_rpmsg_create_ept</code> → <code>__rpmsg_create_ept</code>（virtio_rpmsg_bus.c:). The latter allocates a local address in idr (if<code>chinfo.src == RPMSG_ADDR_ANY</code>then dynamically allocate from 1024), bind the callback<code>rpmsg_ept_cb</code>and<code>priv=eptdev</code>to that address.</li><li>After callback registration, <strong>messages sent remotely with dst equal to this local address will trigger<code>rpmsg_ept_cb</code></strong> (see backend<code>rpmsg_recv_single</code>press<code>msg-&gt;dst</code>look up idr and call<code>ept-&gt;cb</code>）。</li><li><code>get_device</code>/ open failed<code>put_device</code>: ensures the device is not released while the file is open.</li></ul><p>The callback of ept is as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_ept_cb</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev, <span class="type">void</span> *buf, <span class="type">int</span> len,</span></span><br><span class="line"><span class="params"><span class="type">void</span> *priv, u32 addr)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span> =</span> priv;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sk_buff</span> *<span class="title">skb</span>;</span></span><br><span class="line"></span><br><span class="line">skb = alloc_skb(len, GFP_ATOMIC);</span><br><span class="line"><span class="keyword">if</span> (!skb)</span><br><span class="line"><span class="keyword">return</span> -ENOMEM;</span><br><span class="line"></span><br><span class="line">skb_put_data(skb, buf, len);</span><br><span class="line"></span><br><span class="line">spin_lock(&amp;eptdev-&gt;queue_lock);</span><br><span class="line">skb_queue_tail(&amp;eptdev-&gt;<span class="built_in">queue</span>, skb);</span><br><span class="line">spin_unlock(&amp;eptdev-&gt;queue_lock);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* wake up any blocking processes, waiting for new data */</span></span><br><span class="line">wake_up_interruptible(&amp;eptdev-&gt;readq);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>The backend calls ept-&gt;cb in the virtqueue callback (softirq context), so mutex and sleep cannot be used here; use GFP_ATOMIC and spinlock.</li><li>A memory copy (buf → skb) is performed here. The backend obtains the vring buffer with zero-copy during reception, but to pass the data to user space and prevent the buffer from being held by the user for a long time (the backend must return the buffer to rvq as soon as possible), a copy is made into skb.<code>rpmsg_recv_single</code>Immediately after calling cb,<code>virtqueue_add_inbuf</code>return the original buffer.</li></ul><h2 id="rpmsg-eptdev-release">rpmsg_eptdev_release()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_eptdev_release</span><span class="params">(<span class="keyword">struct</span> inode *inode, <span class="keyword">struct</span> file *filp)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span> =</span> cdev_to_eptdev(inode-&gt;i_cdev);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span> =</span> &amp;eptdev-&gt;dev;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Close the endpoint, if it&#x27;s not already destroyed by the parent */</span></span><br><span class="line">mutex_lock(&amp;eptdev-&gt;ept_lock);</span><br><span class="line"><span class="keyword">if</span> (eptdev-&gt;ept) &#123;</span><br><span class="line">rpmsg_destroy_ept(eptdev-&gt;ept);</span><br><span class="line">eptdev-&gt;ept = <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line">mutex_unlock(&amp;eptdev-&gt;ept_lock);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Discard all SKBs */</span></span><br><span class="line">skb_queue_purge(&amp;eptdev-&gt;<span class="built_in">queue</span>);</span><br><span class="line"></span><br><span class="line">put_device(dev);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Actual call<code>dev-&gt;release</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_eptdev_destroy</span><span class="params">(<span class="keyword">struct</span> device *dev, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span> =</span> dev_to_eptdev(dev);</span><br><span class="line"></span><br><span class="line">mutex_lock(&amp;eptdev-&gt;ept_lock);</span><br><span class="line"><span class="keyword">if</span> (eptdev-&gt;ept) &#123;</span><br><span class="line">rpmsg_destroy_ept(eptdev-&gt;ept);</span><br><span class="line">eptdev-&gt;ept = <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line">mutex_unlock(&amp;eptdev-&gt;ept_lock);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* wake up any blocked readers */</span></span><br><span class="line">wake_up_interruptible(&amp;eptdev-&gt;readq);</span><br><span class="line"></span><br><span class="line">cdev_device_del(&amp;eptdev-&gt;cdev, &amp;eptdev-&gt;dev);</span><br><span class="line">put_device(&amp;eptdev-&gt;dev);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="rpmsg-eptdev-read-iter">rpmsg_eptdev_read_iter()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">ssize_t</span> <span class="title function_">rpmsg_eptdev_read_iter</span><span class="params">(<span class="keyword">struct</span> kiocb *iocb, <span class="keyword">struct</span> iov_iter *to)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">filp</span> =</span> iocb-&gt;ki_filp;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span> =</span> filp-&gt;private_data;</span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> flags;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sk_buff</span> *<span class="title">skb</span>;</span></span><br><span class="line"><span class="type">int</span> use;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!eptdev-&gt;ept)</span><br><span class="line"><span class="keyword">return</span> -EPIPE;</span><br><span class="line"></span><br><span class="line">spin_lock_irqsave(&amp;eptdev-&gt;queue_lock, flags);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Wait for data in the queue */</span></span><br><span class="line"><span class="keyword">if</span> (skb_queue_empty(&amp;eptdev-&gt;<span class="built_in">queue</span>)) &#123;</span><br><span class="line">spin_unlock_irqrestore(&amp;eptdev-&gt;queue_lock, flags);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (filp-&gt;f_flags &amp; O_NONBLOCK)</span><br><span class="line"><span class="keyword">return</span> -EAGAIN;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Wait until we get data or the endpoint goes away */</span></span><br><span class="line"><span class="keyword">if</span> (wait_event_interruptible(eptdev-&gt;readq,</span><br><span class="line">     !skb_queue_empty(&amp;eptdev-&gt;<span class="built_in">queue</span>) ||</span><br><span class="line">     !eptdev-&gt;ept))</span><br><span class="line"><span class="keyword">return</span> -ERESTARTSYS;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* We lost the endpoint while waiting */</span></span><br><span class="line"><span class="keyword">if</span> (!eptdev-&gt;ept)</span><br><span class="line"><span class="keyword">return</span> -EPIPE;</span><br><span class="line"></span><br><span class="line">spin_lock_irqsave(&amp;eptdev-&gt;queue_lock, flags);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">skb = skb_dequeue(&amp;eptdev-&gt;<span class="built_in">queue</span>);</span><br><span class="line">spin_unlock_irqrestore(&amp;eptdev-&gt;queue_lock, flags);</span><br><span class="line"><span class="keyword">if</span> (!skb)</span><br><span class="line"><span class="keyword">return</span> -EFAULT;</span><br><span class="line"></span><br><span class="line">use = <span class="type">min_t</span>(<span class="type">size_t</span>, iov_iter_count(to), skb-&gt;len);</span><br><span class="line"><span class="keyword">if</span> (copy_to_iter(skb-&gt;data, use, to) != use)</span><br><span class="line">use = -EFAULT;</span><br><span class="line"></span><br><span class="line">kfree_skb(skb);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> use;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>The wait condition also checks<code>!ept</code>: this way<strong>When destroy sets ept to NULL and calls wake_up, the blocked read can immediately wake up and return -EPIPE, without being stuck forever</strong>. This is the standard way to use “resource disappearance” as a wake-up condition.</li><li>One read retrieves one message: rpmsg is a protocol with clear message boundaries,<strong>one skb = one rpmsg message</strong>。<code>use = min_t(size_t, iov_iter_count(to), skb-&gt;len);</code>meaning if the user buffer is smaller than the message, the excess is discarded (skb is directly freed). This is a pitfall for beginners: the buffer must be large enough (the backend buffer is 512 bytes minus a 16-byte header = 496 bytes payload).</li><li>Use<code>spin_lock_irqsave</code>instead of<code>spin_lock</code>: because reading may occur in a normal process context, but the lock may be held by a callback in interrupt context; disabling interrupts is safer.</li></ul><h2 id="rpmsg-eptdev-write-iter">rpmsg_eptdev_write_iter()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">ssize_t</span> <span class="title function_">rpmsg_eptdev_write_iter</span><span class="params">(<span class="keyword">struct</span> kiocb *iocb,</span></span><br><span class="line"><span class="params">       <span class="keyword">struct</span> iov_iter *from)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">filp</span> =</span> iocb-&gt;ki_filp;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span> =</span> filp-&gt;private_data;</span><br><span class="line"><span class="type">size_t</span> len = iov_iter_count(from);</span><br><span class="line"><span class="type">void</span> *kbuf;</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">kbuf = kzalloc(len, GFP_KERNEL);</span><br><span class="line"><span class="keyword">if</span> (!kbuf)</span><br><span class="line"><span class="keyword">return</span> -ENOMEM;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!copy_from_iter_full(kbuf, len, from)) &#123;</span><br><span class="line">ret = -EFAULT;</span><br><span class="line"><span class="keyword">goto</span> free_kbuf;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (mutex_lock_interruptible(&amp;eptdev-&gt;ept_lock)) &#123;</span><br><span class="line">ret = -ERESTARTSYS;</span><br><span class="line"><span class="keyword">goto</span> free_kbuf;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!eptdev-&gt;ept) &#123;</span><br><span class="line">ret = -EPIPE;</span><br><span class="line"><span class="keyword">goto</span> unlock_eptdev;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (filp-&gt;f_flags &amp; O_NONBLOCK)</span><br><span class="line">ret = rpmsg_trysend(eptdev-&gt;ept, kbuf, len);</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">ret = rpmsg_send(eptdev-&gt;ept, kbuf, len);</span><br><span class="line"></span><br><span class="line">unlock_eptdev:</span><br><span class="line">mutex_unlock(&amp;eptdev-&gt;ept_lock);</span><br><span class="line"></span><br><span class="line">free_kbuf:</span><br><span class="line">kfree(kbuf);</span><br><span class="line"><span class="keyword">return</span> ret &lt; <span class="number">0</span> ? ret : len;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>First<code>copy_from_iter</code>then acquire the lock, because<strong>user-space copy may cause a page fault and sleep</strong>, which should not be done while holding ept_lock—otherwise it would block the destroy path for a long time.</p></li><li><p><code>rpmsg_send</code>The blocking version goes all the way to the backend<code>rpmsg_send_offchannel_raw(..., wait=true)</code>: if no TX buffer, then<code>wait_event_interruptible_timeout(..., 15000)</code>。<code>rpmsg_trysend</code>is<code>wait=false</code>, if no buffer, immediately<code>-ENOMEM</code>。</p></li><li><p>On success, returns len (number of bytes written), not ret (backend ret is 0). Note that a single message is limited by the backend buffer:<code>len &gt; buf_size - sizeof(hdr)</code>That is, 496 bytes will<code>-EMSGSIZE</code>。</p></li><li><p>Sending is also one write = one message, without streaming concatenation.</p></li></ul><h2 id="rpmsg-eptdev-poll">rpmsg_eptdev_poll()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">__poll_t</span> <span class="title function_">rpmsg_eptdev_poll</span><span class="params">(<span class="keyword">struct</span> file *filp, poll_table *wait)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span> =</span> filp-&gt;private_data;</span><br><span class="line"><span class="type">__poll_t</span> mask = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!eptdev-&gt;ept)</span><br><span class="line"><span class="keyword">return</span> EPOLLERR;</span><br><span class="line"></span><br><span class="line">poll_wait(filp, &amp;eptdev-&gt;readq, wait);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!skb_queue_empty(&amp;eptdev-&gt;<span class="built_in">queue</span>))</span><br><span class="line">mask |= EPOLLIN | EPOLLRDNORM;</span><br><span class="line"></span><br><span class="line">mask |= rpmsg_poll(eptdev-&gt;ept, filp, wait);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> mask;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="rpmsg-eptdev-ioctl">rpmsg_eptdev_ioctl()</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">long</span> <span class="title function_">rpmsg_eptdev_ioctl</span><span class="params">(<span class="keyword">struct</span> file *fp, <span class="type">unsigned</span> <span class="type">int</span> cmd,</span></span><br><span class="line"><span class="params">       <span class="type">unsigned</span> <span class="type">long</span> arg)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_eptdev</span> *<span class="title">eptdev</span> =</span> fp-&gt;private_data;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (cmd != RPMSG_DESTROY_EPT_IOCTL)</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> rpmsg_eptdev_destroy(&amp;eptdev-&gt;dev, <span class="literal">NULL</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>rpmsg_poll forwarded to the backend’s<code>ops-&gt;poll</code>— but note the virtio backend’s<code>virtio_endpoint_ops</code>does not implement poll, so<code>rpmsg_poll</code>in<code>if (!ept-&gt;ops-&gt;poll) return 0</code>, that is, under this backend, poll only reports readable, not writable. This is an optional backend implementation.</p><h1 id="References">References</h1><div class="reference-source"><span class="hidden-anchor" id="referfrom_[1]"></span><a class="reference-anchor" href="#referto_[1]">[1]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Asymmetric Multiprocessingand Embedded Linux" href="http://events17.linuxfoundation.org/sites/events/files/slides/NOVAK_CERVENKA.pdf">Asymmetric Multiprocessingand Embedded Linux</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[2]"></span><a class="reference-anchor" href="#referto_[2]">[2]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Using virtio to Talk With Remote Processors" href="https://events.linuxfoundation.org/images/stories/pdf/lf_elc12_ben-cohen.pdf">Using virtio to Talk With Remote Processors</a></div>]]></content>
    
    
    <summary type="html">This article introduces the implementation mechanism of the Rpmsg Char Driver character device driver based on Linux 5.10.x. It discusses in detail the classic architecture design where the control device and endpoint device are separated, and summarizes the specific processes and key code logic of driver registration, delayed endpoint creation, lock and wait queue synchronization mechanisms, as well as user-space message sending and receiving.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>Rpmsg Core</title>
    <link href="https://even629.com/en/posts/202606270/"/>
    <id>https://even629.com/en/posts/202606270/</id>
    <published>2026-06-27T07:17:13.000Z</published>
    <updated>2026-06-27T07:17:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-06-27</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the bus abstraction mechanism of Rpmsg Core in Linux 5.10.23 and the access method of its backend, and discusses in detail the matching and scoring rules between devices and drivers as well as the device probing process. It summarizes core logic such as power domain association, automatic endpoint creation, and dynamic address allocation during probing, revealing the implementation details of the rpmsg framework in hardware power management and endpoint communication.</blockquote><hr><blockquote><p>linux 5.10.23</p></blockquote><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/shared/05.png" alt="rpmsg.drawio"><figcaption>rpmsg.drawio</figcaption></figure></p><p><strong>rpmsg is a bus abstraction that is not tied to any specific transport</strong>. Virtio is the most common implementation in Linux currently, but theoretically there can be:</p><ul><li>A direct mapping implementation based on shared memory</li><li>An implementation based on mailbox interrupts</li><li>An implementation based on PCIe doorbell</li></ul><p>Each backend only needs to provide its own<code>rpmsg_endpoint_ops</code>and<code>rpmsg_device_ops</code>, to connect to the rpmsg core. Moreover, not all backends need to support all send variants. For example:</p><ul><li>The simplest backend only needs to implement send and trysend.</li><li>If the backend does not support explicitly specifying src/dst (offchannel), it can</li><li>If the backend does not support poll, user-space write operations are still available (blocking/non-blocking modes are guaranteed by the<code>rpmsg_send/rpmsg_trysend</code>semantics).</li></ul><h1 id="module-init-module-exit">module_init/module_exit</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">rpmsg_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">ret = bus_register(&amp;rpmsg_bus);</span><br><span class="line"><span class="keyword">if</span> (ret)</span><br><span class="line">pr_err(<span class="string">&quot;failed to register rpmsg bus: %d\n&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line">postcore_initcall(rpmsg_init);</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> __exit <span class="title function_">rpmsg_fini</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">bus_unregister(&amp;rpmsg_bus);</span><br><span class="line">&#125;</span><br><span class="line">module_exit(rpmsg_fini);</span><br><span class="line"></span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;remote processor messaging bus&quot;</span>);</span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL v2&quot;</span>);</span><br></pre></td></tr></table></figure><p><code>rpmsg_init</code>function usage<code>postcore_initcall</code>, call<code>bus_register</code>register a bus</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// include/linux/init.h</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __initcall(fn) device_initcall(fn)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> pure_initcall(fn)__define_initcall(fn, 0)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> core_initcall(fn)__define_initcall(fn, 1)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> core_initcall_sync(fn)__define_initcall(fn, 1s)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> postcore_initcall(fn)__define_initcall(fn, 2)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> postcore_initcall_sync(fn)__define_initcall(fn, 2s)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> arch_initcall(fn)__define_initcall(fn, 3)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> arch_initcall_sync(fn)__define_initcall(fn, 3s)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> subsys_initcall(fn)__define_initcall(fn, 4)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> subsys_initcall_sync(fn)__define_initcall(fn, 4s)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> fs_initcall(fn)__define_initcall(fn, 5)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> fs_initcall_sync(fn)__define_initcall(fn, 5s)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> rootfs_initcall(fn)__define_initcall(fn, rootfs)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> device_initcall(fn)__define_initcall(fn, 6)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> device_initcall_sync(fn)__define_initcall(fn, 6s)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> late_initcall(fn)__define_initcall(fn, 7)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> late_initcall_sync(fn)__define_initcall(fn, 7s)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="title function_">int</span> <span class="params">(*<span class="type">initcall_t</span>)</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> CONFIG_HAVE_ARCH_PREL32_RELOCATIONS</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ___define_initcall(fn, id, __sec)\</span></span><br><span class="line"><span class="meta">__ADDRESSABLE(fn)\</span></span><br><span class="line"><span class="meta">asm(<span class="string">&quot;.section\&quot;&quot;</span> #__sec <span class="string">&quot;.init\&quot;, \&quot;a\&quot;\n&quot;</span>\</span></span><br><span class="line"><span class="meta"><span class="string">&quot;__initcall_&quot;</span> #fn #id <span class="string">&quot;:\n&quot;</span>\</span></span><br><span class="line"><span class="meta">    <span class="string">&quot;.long&quot;</span> #fn <span class="string">&quot; - .\n&quot;</span>\</span></span><br><span class="line"><span class="meta">    <span class="string">&quot;.previous\n&quot;</span>);</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ___define_initcall(fn, id, __sec) \</span></span><br><span class="line"><span class="meta">static initcall_t __initcall_##fn##id __used \</span></span><br><span class="line"><span class="meta">__attribute__((__section__(#__sec <span class="string">&quot;.init&quot;</span>))) = fn;</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h1 id="struct-bust-type-rpmsg-bus"><code>struct bust_type rpmsg_bus</code></h1><p><code>struct bus_type rpmsg_bus</code>is defined as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">bus_type</span> <span class="title">rpmsg_bus</span> =</span> &#123;</span><br><span class="line">.name= <span class="string">&quot;rpmsg&quot;</span>,</span><br><span class="line">.match= rpmsg_dev_match,</span><br><span class="line">.dev_groups= rpmsg_dev_groups,</span><br><span class="line">.uevent= rpmsg_uevent,</span><br><span class="line">.probe= rpmsg_dev_probe,</span><br><span class="line">.remove= rpmsg_dev_remove,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="rpmsg-dev-match">rpmsg_dev_match</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* match rpmsg channel and rpmsg driver */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_dev_match</span><span class="params">(<span class="keyword">struct</span> device *dev, <span class="keyword">struct</span> device_driver *drv)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> to_rpmsg_device(dev);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_driver</span> *<span class="title">rpdrv</span> =</span> to_rpmsg_driver(drv);</span><br><span class="line"><span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_id</span> *<span class="title">ids</span> =</span> rpdrv-&gt;id_table;</span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> i;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (rpdev-&gt;driver_override)</span><br><span class="line"><span class="keyword">return</span> !<span class="built_in">strcmp</span>(rpdev-&gt;driver_override, drv-&gt;name);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ids)</span><br><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; ids[i].name[<span class="number">0</span>]; i++)</span><br><span class="line"><span class="keyword">if</span> (rpmsg_id_match(rpdev, &amp;ids[i]))</span><br><span class="line"><span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> of_driver_match_device(dev, drv);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>if<code>rpdev-&gt;driver_override</code>then only need to compare<code>rpdev-&gt;driver_override</code>and<code>drv-&gt;name</code>, i.e., specify the<code>rpdev</code>force match a driver with a corresponding name</p></li><li><p>if<code>rpdev-&gt;id_talbe</code>exists</p><ul><li><p>from<code>struct rpmsg_driver *rpdrv</code>extract<code>const struct rpmsg_device_id *ids</code>then, traverse the ids table, through<code>ids[i].name</code>match<code>rpmsg_device</code>, if match succeeds, return 1,</p></li><li><p>otherwise call<code>of_driver_match_device</code>match<code>struct device *dev</code>and<code>struct device_driver *drv</code></p></li></ul></li></ul><p><code>of_driver_match_device</code>’s match passes<code>struct device_driver *drv</code>in<code>drv-&gt;of_match_table</code>and<code>struct device *dev</code>in<code>dev-&gt;of_node</code>as parameters, call<code>__of_match_node</code>match:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span></span><br><span class="line"><span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">of_device_id</span> *__<span class="title">of_match_node</span>(<span class="title">const</span> <span class="keyword">struct</span> <span class="title">of_device_id</span> *<span class="title">matches</span>,</span></span><br><span class="line"><span class="class">   <span class="title">const</span> <span class="keyword">struct</span> <span class="title">device_node</span> *<span class="title">node</span>)</span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">of_device_id</span> *<span class="title">best_match</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"><span class="type">int</span> score, best_score = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!matches)</span><br><span class="line"><span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (; matches-&gt;name[<span class="number">0</span>] || matches-&gt;type[<span class="number">0</span>] || matches-&gt;compatible[<span class="number">0</span>]; matches++) &#123;</span><br><span class="line">score = __of_device_is_compatible(node, matches-&gt;compatible,</span><br><span class="line">  matches-&gt;type, matches-&gt;name);</span><br><span class="line"><span class="keyword">if</span> (score &gt; best_score) &#123;</span><br><span class="line">best_match = matches;</span><br><span class="line">best_score = score;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> best_match;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>pass<code>__of_device_is_compatible</code>calculate the score, find the one with the highest score<code>const struct of_device_id *best_match</code>, and<code>__of_device_is_compatible</code>is defined as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * __of_device_is_compatible() - Check if the node matches given constraints</span></span><br><span class="line"><span class="comment"> * @device: pointer to node</span></span><br><span class="line"><span class="comment"> * @compat: required compatible string, NULL or &quot;&quot; for any match</span></span><br><span class="line"><span class="comment"> * @type: required device_type value, NULL or &quot;&quot; for any match</span></span><br><span class="line"><span class="comment"> * @name: required node name, NULL or &quot;&quot; for any match</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Checks if the given @compat, @type and @name strings match the</span></span><br><span class="line"><span class="comment"> * properties of the given @device. A constraints can be skipped by</span></span><br><span class="line"><span class="comment"> * passing NULL or an empty string as the constraint.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 for no match, and a positive integer on match. The return</span></span><br><span class="line"><span class="comment"> * value is a relative score with larger values indicating better</span></span><br><span class="line"><span class="comment"> * matches. The score is weighted for the most specific compatible value</span></span><br><span class="line"><span class="comment"> * to get the highest score. Matching type is next, followed by matching</span></span><br><span class="line"><span class="comment"> * name. Practically speaking, this results in the following priority</span></span><br><span class="line"><span class="comment"> * order for matches:</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 1. specific compatible &amp;&amp; type &amp;&amp; name</span></span><br><span class="line"><span class="comment"> * 2. specific compatible &amp;&amp; type</span></span><br><span class="line"><span class="comment"> * 3. specific compatible &amp;&amp; name</span></span><br><span class="line"><span class="comment"> * 4. specific compatible</span></span><br><span class="line"><span class="comment"> * 5. general compatible &amp;&amp; type &amp;&amp; name</span></span><br><span class="line"><span class="comment"> * 6. general compatible &amp;&amp; type</span></span><br><span class="line"><span class="comment"> * 7. general compatible &amp;&amp; name</span></span><br><span class="line"><span class="comment"> * 8. general compatible</span></span><br><span class="line"><span class="comment"> * 9. type &amp;&amp; name</span></span><br><span class="line"><span class="comment"> * 10. type</span></span><br><span class="line"><span class="comment"> * 11. name</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> __of_device_is_compatible(<span class="type">const</span> <span class="keyword">struct</span> device_node *device,</span><br><span class="line">     <span class="type">const</span> <span class="type">char</span> *compat, <span class="type">const</span> <span class="type">char</span> *type, <span class="type">const</span> <span class="type">char</span> *name)</span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">property</span> *<span class="title">prop</span>;</span></span><br><span class="line"><span class="type">const</span> <span class="type">char</span> *cp;</span><br><span class="line"><span class="type">int</span> index = <span class="number">0</span>, score = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Compatible match has highest priority */</span></span><br><span class="line"><span class="keyword">if</span> (compat &amp;&amp; compat[<span class="number">0</span>]) &#123;</span><br><span class="line">prop = __of_find_property(device, <span class="string">&quot;compatible&quot;</span>, <span class="literal">NULL</span>);</span><br><span class="line"><span class="keyword">for</span> (cp = of_prop_next_string(prop, <span class="literal">NULL</span>); cp;</span><br><span class="line">     cp = of_prop_next_string(prop, cp), index++) &#123;</span><br><span class="line"><span class="keyword">if</span> (of_compat_cmp(cp, compat, <span class="built_in">strlen</span>(compat)) == <span class="number">0</span>) &#123;</span><br><span class="line">score = INT_MAX/<span class="number">2</span> - (index &lt;&lt; <span class="number">2</span>);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (!score)</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Matching type is better than matching name */</span></span><br><span class="line"><span class="keyword">if</span> (type &amp;&amp; type[<span class="number">0</span>]) &#123;</span><br><span class="line"><span class="keyword">if</span> (!__of_node_is_type(device, type))</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">score += <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Matching name is a bit better than not */</span></span><br><span class="line"><span class="keyword">if</span> (name &amp;&amp; name[<span class="number">0</span>]) &#123;</span><br><span class="line"><span class="keyword">if</span> (!of_node_name_eq(device, name))</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">score++;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> score;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>=</mo><mi>I</mi><mi>N</mi><mi>T</mi><mi mathvariant="normal">_</mi><mi>M</mi><mi>A</mi><mi>X</mi><mi mathvariant="normal">/</mi><mn>2</mn></mrow><annotation encoding="application/x-tex">Base = INT\_MAX / 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.06em;vertical-align:-0.31em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord" style="margin-right:0.02778em;">_</span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mord">/2</span></span></span></span></p></blockquote><div class="table-wrap"><table><thead><tr><th><strong>priority</strong></th><th><strong>Drive Constraint Combination</strong></th><th><strong>Match Detail Conditions</strong></th><th><strong>Score Calculation Formula</strong></th><th><strong>Final Score Example</strong></th></tr></thead><tbody><tr><td><strong>1</strong></td><td>specific <code>compat</code> &amp;&amp; <code>type</code> &amp;&amp; <code>name</code></td><td><code>compat</code>matches and<code>index=0</code>；<code>type</code>matches;<code>name</code>matches</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>0</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mn>2</mn><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">Base - (0 \times 4) + 2 + 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>+</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">Base + 3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span></span></span></span></strong> (Highest Score)</td></tr><tr><td><strong>2</strong></td><td>specific <code>compat</code> &amp;&amp; <code>type</code></td><td><code>compat</code>matches and<code>index=0</code>；<code>type</code>matches; no<code>name</code>constraint</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>0</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mn>2</mn><mo>+</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">Base - (0 \times 4) + 2 + 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>+</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">Base + 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span></strong></td></tr><tr><td><strong>3</strong></td><td>specific <code>compat</code> &amp;&amp; <code>name</code></td><td><code>compat</code>matches and<code>index=0</code>; no<code>type</code>constraint;<code>name</code>matches</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>0</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mn>0</mn><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">Base - (0 \times 4) + 0 + 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">Base + 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></strong></td></tr><tr><td><strong>4</strong></td><td>specific <code>compat</code></td><td><code>compat</code>matches and<code>index=0</code>; no<code>type</code>and<code>name</code>constraints</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>0</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mn>0</mn><mo>+</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">Base - (0 \times 4) + 0 + 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi></mrow><annotation encoding="application/x-tex">Base</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span></span></span></span></strong></td></tr><tr><td><strong>5</strong></td><td>general <code>compat</code> &amp;&amp; <code>type</code> &amp;&amp; <code>name</code></td><td><code>compat</code>matches and<code>index=1</code>；<code>type</code>matches;<code>name</code>matches</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>1</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mn>2</mn><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">Base - (1 \times 4) + 2 + 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">Base - 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></strong></td></tr><tr><td><strong>6</strong></td><td>general <code>compat</code> &amp;&amp; <code>type</code></td><td><code>compat</code>matches and<code>index=1</code>；<code>type</code>matches; no<code>name</code>constraint</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>1</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mn>2</mn><mo>+</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">Base - (1 \times 4) + 2 + 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">Base - 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span></strong></td></tr><tr><td><strong>7</strong></td><td>general <code>compat</code> &amp;&amp; <code>name</code></td><td><code>compat</code>matches and<code>index=1</code>; no<code>type</code>constraint;<code>name</code>matches</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>1</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mn>0</mn><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">Base - (1 \times 4) + 0 + 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">Base - 3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span></span></span></span></strong></td></tr><tr><td><strong>8</strong></td><td>general <code>compat</code></td><td><code>compat</code>matches and<code>index=1</code>; none<code>type</code>and<code>name</code>constraint</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>1</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mn>0</mn><mo>+</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">Base - (1 \times 4) + 0 + 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mn>4</mn></mrow><annotation encoding="application/x-tex">Base - 4</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">4</span></span></span></span></strong></td></tr><tr><td>—</td><td><em>more generalized compat…</em></td><td><em><code>compat</code>matches and<code>index=2</code>(later compatible string)</em></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi><mi>a</mi><mi>s</mi><mi>e</mi><mo>−</mo><mo stretchy="false">(</mo><mn>2</mn><mo>×</mo><mn>4</mn><mo stretchy="false">)</mo><mo>+</mo><mo>…</mo></mrow><annotation encoding="application/x-tex">Base - (2 \times 4) + \dots</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord mathnormal">a</span><span class="mord mathnormal">se</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">4</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.123em;"></span><span class="minner">…</span></span></span></span></td><td><em>continues to decrease as index increases</em></td></tr><tr><td><strong>9</strong></td><td><code>type</code> &amp;&amp; <code>name</code></td><td>none<code>compat</code>constraint;<code>type</code>matches;<code>name</code>matches</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>+</mo><mn>2</mn><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">0 + 2 + 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn></mrow><annotation encoding="application/x-tex">3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">3</span></span></span></span></strong></td></tr><tr><td><strong>10</strong></td><td><code>type</code></td><td>none<code>compat</code>constraint;<code>type</code>matches; none<code>name</code>constraint</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>+</mo><mn>2</mn><mo>+</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">0 + 2 + 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn></mrow><annotation encoding="application/x-tex">2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">2</span></span></span></span></strong></td></tr><tr><td><strong>11</strong></td><td><code>name</code></td><td>none<code>compat</code>constraint; none<code>type</code>constraint;<code>name</code>match</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>+</mo><mn>0</mn><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">0 + 0 + 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.7278em;vertical-align:-0.0833em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn></mrow><annotation encoding="application/x-tex">1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></strong>(lowest valid score)</td></tr><tr><td><strong>—</strong></td><td><strong>mismatch / elimination</strong></td><td>any driver-specified constraint not found in the node</td><td>return directly<code>0</code></td><td><strong><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn></mrow><annotation encoding="application/x-tex">0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span></strong></td></tr></tbody></table></div><h2 id="rpmsg-dev-probe">rpmsg_dev_probe</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * when an rpmsg driver is probed with a channel, we seamlessly create</span></span><br><span class="line"><span class="comment"> * it an endpoint, binding its rx callback to a unique local rpmsg</span></span><br><span class="line"><span class="comment"> * address.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * if we need to, we also announce about this channel to the remote</span></span><br><span class="line"><span class="comment"> * processor (needed in case the driver is exposing an rpmsg service).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_dev_probe</span><span class="params">(<span class="keyword">struct</span> device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> to_rpmsg_device(dev);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_driver</span> *<span class="title">rpdrv</span> =</span> to_rpmsg_driver(rpdev-&gt;dev.driver);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span> =</span> &#123;&#125;;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line"><span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">err = dev_pm_domain_attach(dev, <span class="literal">true</span>);</span><br><span class="line"><span class="keyword">if</span> (err)</span><br><span class="line"><span class="keyword">goto</span> out;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (rpdrv-&gt;callback) &#123;</span><br><span class="line"><span class="built_in">strncpy</span>(chinfo.name, rpdev-&gt;id.name, RPMSG_NAME_SIZE);</span><br><span class="line">chinfo.src = rpdev-&gt;src;</span><br><span class="line">chinfo.dst = RPMSG_ADDR_ANY;</span><br><span class="line"></span><br><span class="line">ept = rpmsg_create_ept(rpdev, rpdrv-&gt;callback, <span class="literal">NULL</span>, chinfo);</span><br><span class="line"><span class="keyword">if</span> (!ept) &#123;</span><br><span class="line">dev_err(dev, <span class="string">&quot;failed to create endpoint\n&quot;</span>);</span><br><span class="line">err = -ENOMEM;</span><br><span class="line"><span class="keyword">goto</span> out;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">rpdev-&gt;ept = ept;</span><br><span class="line">rpdev-&gt;src = ept-&gt;addr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">err = rpdrv-&gt;probe(rpdev);</span><br><span class="line"><span class="keyword">if</span> (err) &#123;</span><br><span class="line">dev_err(dev, <span class="string">&quot;%s: failed: %d\n&quot;</span>, __func__, err);</span><br><span class="line"><span class="keyword">goto</span> destroy_ept;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ept &amp;&amp; rpdev-&gt;ops-&gt;announce_create) &#123;</span><br><span class="line">err = rpdev-&gt;ops-&gt;announce_create(rpdev);</span><br><span class="line"><span class="keyword">if</span> (err) &#123;</span><br><span class="line">dev_err(dev, <span class="string">&quot;failed to announce creation\n&quot;</span>);</span><br><span class="line"><span class="keyword">goto</span> remove_rpdev;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">remove_rpdev:</span><br><span class="line"><span class="keyword">if</span> (rpdrv-&gt;remove)</span><br><span class="line">rpdrv-&gt;remove(rpdev);</span><br><span class="line">destroy_ept:</span><br><span class="line"><span class="keyword">if</span> (ept)</span><br><span class="line">rpmsg_destroy_ept(ept);</span><br><span class="line">out:</span><br><span class="line"><span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li><strong>power domain association</strong></li></ol> <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">err = dev_pm_domain_attach(dev, <span class="literal">true</span>);</span><br><span class="line"> <span class="keyword">if</span> (err)</span><br><span class="line">     <span class="keyword">goto</span> out;</span><br></pre></td></tr></table></figure><p>Purpose: associate the device with a Power Management Domain (genpd).</p><ul><li>In modern SoCs, different peripherals may belong to different power domains and can be independently switched on/off</li><li><code>dev_pm_domain_attach(dev, true) </code>the true in it means: if the device tree specifies the device’s<code>power-domains</code>property, the kernel will attempt to automatically attach</li><li>if attach fails (e.g., power domain does not exist), subsequent initialization is meaningless, exit directly</li></ul><blockquote><p>Placed first because subsequent endpoint creation and driver initialization may depend on the hardware power being already on. If the power domain is not ready, these operations may fail or even cause hardware anomalies.</p></blockquote><hr><ol start="2"><li><strong>Automatically create Endpoint</strong></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (rpdrv-&gt;callback) &#123;</span><br><span class="line"><span class="built_in">strncpy</span>(chinfo.name, rpdev-&gt;id.name, RPMSG_NAME_SIZE);</span><br><span class="line">chinfo.src = rpdev-&gt;src;</span><br><span class="line">chinfo.dst = RPMSG_ADDR_ANY;</span><br><span class="line"></span><br><span class="line">ept = rpmsg_create_ept(rpdev, rpdrv-&gt;callback, <span class="literal">NULL</span>, chinfo);</span><br><span class="line"><span class="keyword">if</span> (!ept) &#123;</span><br><span class="line">dev_err(dev, <span class="string">&quot;failed to create endpoint\n&quot;</span>);</span><br><span class="line">err = -ENOMEM;</span><br><span class="line"><span class="keyword">goto</span> out;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">rpdev-&gt;ept = ept;</span><br><span class="line">rpdev-&gt;src = ept-&gt;addr;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>First determine<code>if (rpdrv-&gt;callback)</code></p><ul><li>Simple driver: only needs one receive callback, provide callback during registration, framework automatically creates endpoint for it</li><li>Complex driver: may require multiple endpoints, dynamic address management, the callback of such drivers may be NULL, they manually call in their own probe<code>rpmsg_create_ept()</code>,</li></ul><p>then construct<code>struct rpmsg_channel_info chipinfo</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">strncpy(chinfo.name, rpdev-&gt;id.name, RPMSG_NAME_SIZE);  // Service name</span><br><span class="line">chinfo.src = rpdev-&gt;src;                                  // Local address</span><br><span class="line">chinfo.dst = RPMSG_ADDR_ANY;                              // Destination address any</span><br></pre></td></tr></table></figure><blockquote><p>Note<code>dst = RPMSG_ADDR_ANY</code>Meaning: when creating endpoint, it does not bind a fixed peer address, can accept messages from any remote address.</p></blockquote><p>Call<code>rpmsg_create_ept()</code>The parameters passed are<code>struct rpmsg_device *rpdev</code>，<code>rpdrv-&gt;callback</code>，<code>priv = NULL</code>，<code>struct rpmsg_channel_info chinfo</code>, after creating ept, key assignment:<code>rpdev-&gt;src = ept-&gt;addr</code>, this is a very critical operation!</p><ul><li>If before creation<code>rpdev-&gt;src = RPMSG_ADDR_ANY</code>, the backend will dynamically allocate an available address</li><li><code>ept-&gt;addr</code>is the actual local address after backend allocation</li><li>Write<code>ept-&gt;addr</code>back to<code>rpdev-&gt;src</code>, ensuring the device structure records the real address</li></ul><p>This means: the driver’s receive callback will be bound to this newly allocated address, and messages sent from the remote end to this address will trigger the callback.</p><hr><ol start="3"><li><strong>Call the<code>rpdrv</code>’s<code>probe</code>function</strong></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">err = rpdrv-&gt;probe(rpdev);</span><br><span class="line"><span class="keyword">if</span> (err) &#123;</span><br><span class="line">dev_err(dev, <span class="string">&quot;%s: failed: %d\n&quot;</span>, __func__, err);</span><br><span class="line"><span class="keyword">goto</span> destroy_ept;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Call<code>struct rpmsg_driver *rpdrv</code>’s probe function</p><hr><ol start="4"><li><strong>announce_create</strong></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (ept &amp;&amp; rpdev-&gt;ops-&gt;announce_create) &#123;</span><br><span class="line">err = rpdev-&gt;ops-&gt;announce_create(rpdev);</span><br><span class="line"><span class="keyword">if</span> (err) &#123;</span><br><span class="line">dev_err(dev, <span class="string">&quot;failed to announce creation\n&quot;</span>);</span><br><span class="line"><span class="keyword">goto</span> remove_rpdev;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>If<code>struct rpmsg_device *rpdev</code>’s<code>const struct rpmsg_device_ops *ops;</code>'s<code>announce_create</code>is set, then call the<code>announce_create</code>, i.e., called after ept is created<code>announce_create</code>this callback</p><h2 id="rpmsg-dev-remove">rpmsg_dev_remove</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_dev_remove</span><span class="params">(<span class="keyword">struct</span> device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> to_rpmsg_device(dev);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_driver</span> *<span class="title">rpdrv</span> =</span> to_rpmsg_driver(rpdev-&gt;dev.driver);</span><br><span class="line"><span class="type">int</span> err = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (rpdev-&gt;ops-&gt;announce_destroy)</span><br><span class="line">err = rpdev-&gt;ops-&gt;announce_destroy(rpdev);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (rpdrv-&gt;remove)</span><br><span class="line">rpdrv-&gt;remove(rpdev);</span><br><span class="line"></span><br><span class="line">dev_pm_domain_detach(dev, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (rpdev-&gt;ept)</span><br><span class="line">rpmsg_destroy_ept(rpdev-&gt;ept);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The remove function and probe function are in reverse order; first,<code>announce_destroy</code>, then call<code>struct rpmsg_driver *rpdrv</code>the remove function in, then call<code>dev_pm_domain_detach</code>detach the power domain, and finally call<code>rpmsg_destroy_ept</code>destroy<code>rpdev-&gt;ept</code></p><h2 id="rpmsg-uevent">rpmsg_uevent</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_uevent</span><span class="params">(<span class="keyword">struct</span> device *dev, <span class="keyword">struct</span> kobj_uevent_env *env)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> to_rpmsg_device(dev);</span><br><span class="line"><span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">ret = of_device_uevent_modalias(dev, env);</span><br><span class="line"><span class="keyword">if</span> (ret != -ENODEV)</span><br><span class="line"><span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> add_uevent_var(env, <span class="string">&quot;MODALIAS=&quot;</span> RPMSG_DEVICE_MODALIAS_FMT,</span><br><span class="line">rpdev-&gt;id.name);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This function is the callback when an RPMSG bus device generates a uevent (user space event/hotplug event). It serves as the bridge between the kernel device model and user-space udev. Function location and call chain:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">设备注册到 rpmsg_bus</span><br><span class="line">        │</span><br><span class="line">        ▼</span><br><span class="line">device_add()</span><br><span class="line">    └── bus_add_device() / bus_probe_device()</span><br><span class="line">        └── kobject_uevent(KOBJ_ADD)   <span class="comment">// Trigger uevent</span></span><br><span class="line">            └── dev_uevent()            <span class="comment">// Device&#x27;s uevent callback</span></span><br><span class="line">                └── rpmsg_uevent()      <span class="comment">// ← This is where (via bus_type.uevent)</span></span><br></pre></td></tr></table></figure><p>The uevent carries a set of environment variables to user space, and udev decides based on these variables:</p><ul><li>Create device node</li><li>Automatically load driver module</li><li>Execute rule script</li></ul><p>Line-by-line code analysis</p><ol><li><strong>First priority: Device tree format modalias</strong></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ret = of_device_uevent_modalias(dev, env);</span><br><span class="line"><span class="keyword">if</span> (ret != -ENODEV)</span><br><span class="line">    <span class="keyword">return</span> ret;</span><br></pre></td></tr></table></figure><p>If the device is associated with a device tree node (dev-&gt;of_node),<code>of_device_uevent_modalias</code>it will:</p><ol><li>Read the compatible property of the device tree</li><li>Generate the standard OF modalias format:<code>of:N&lt;name&gt;T&lt;type&gt;C&lt;compatible&gt;</code></li><li>Add to the uevent environment variable</li></ol><p>Return value meaning:</p><ul><li><code>0</code>: Successfully added OF modalias, return directly</li><li><code>-ENODEV</code>: Device has no device tree node, continue with RPMSG’s own logic</li></ul><hr><pre><code>2. **Second priority: RPMSG custom modalias**</code></pre><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">return</span> add_uevent_var(env, <span class="string">&quot;MODALIAS=&quot;</span> RPMSG_DEVICE_MODALIAS_FMT,</span><br><span class="line">                rpdev-&gt;id.name);</span><br></pre></td></tr></table></figure><p>If the device has no device tree node, RPMSG generates its own modalias:</p><p><code>RPMSG_DEVICE_MODALIAS_FMT</code>Defined (in<code>include/linux/rpmsg.h</code>or<code>mod_devicetable.h</code>):</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_DEVICE_MODALIAS_FMT   <span class="string">&quot;rpmsg:%s&quot;</span></span></span><br></pre></td></tr></table></figure><p>Example of the final generated uevent environment variables:<code>MODALIAS=rpmsg:rpmsg-tty</code></p><hr><ol start="3"><li><strong>Complete uevent output example</strong></li></ol><p>When a new RPMSG device is registered, the uevent might look like this:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">ACTION=add</span><br><span class="line">BUS=rpmsg</span><br><span class="line">SUBSYSTEM=rpmsg</span><br><span class="line">MODALIAS=rpmsg:rpmsg-tty       ← 这里由 rpmsg_uevent 生成</span><br><span class="line">NAME=rpmsg-tty</span><br><span class="line">SRC=0x401</span><br><span class="line">DST=0x0</span><br><span class="line">DEVPATH=/bus/rpmsg/devices/virtio0.rpmsg-tty.-1.0</span><br></pre></td></tr></table></figure><p>How does udev utilize modalias?</p><ul><li>Automatically loading driver modules: udev rules typically include:</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># /lib/udev/rules.d/80-drivers.rules</span><br><span class="line"></span><br><span class="line">ENV&#123;MODALIAS&#125;==&quot;?*&quot;, RUN&#123;builtin&#125;+=&quot;kmod load $env&#123;MODALIAS&#125;&quot;</span><br></pre></td></tr></table></figure><p>When the uevent carries<code>MODALIAS=rpmsg:rpmsg-tty</code>, udev will execute:<code>modprobe rpmsg:rpmsg-tty</code></p><p>However, modprobe does not recognize the format with colons; the module itself needs to match via aliases.</p><ul><li>Alias declaration in the driver module: In the driver source code:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_id</span> <span class="title">rpmsg_tty_id_table</span>[] =</span> &#123;</span><br><span class="line">    &#123; .name = <span class="string">&quot;rpmsg-tty&quot;</span> &#125;,</span><br><span class="line">    &#123; &#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">MODULE_DEVICE_TABLE(rpmsg, rpmsg_tty_id_table);   <span class="comment">// ← Generate module alias</span></span><br></pre></td></tr></table></figure><p>After compilation, the module file will contain alias information:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ modinfo rpmsg_tty</span><br><span class="line">  <span class="built_in">alias</span>:          rpmsg:<span class="built_in">tty</span>*</span><br></pre></td></tr></table></figure><blockquote><p>Note:<code>MODULE_DEVICE_TABLE</code>The macro generates at compile time__mod_rpmsg__… symbol, depmod will write it into<code>/lib/modules/$(uname -r)/modules.alias</code>。</p></blockquote><p><code>udev</code> → <code>modprobe</code>the complete chain</p><p>Kernel:<code>rpmsg_uevent()</code><br>│<br>▼ Generate</p><p><code>MODALIAS=rpmsg:rpmsg-tty</code><br>│<br>▼ Via<code>netlink/socket</code>Send to user space<br><code>udevd</code>Received<code>uevent</code><br>│<br>▼ Parse environment variables<br><code>MODALIAS=rpmsg:rpmsg-tty</code><br>│<br>▼ Execute rules<br><code>modprobe rpmsg:rpmsg-tty</code><br>│<br>▼ Match<code>/lib/modules/.../modules.alias</code><br>Found<code>rpmsg_tty.ko</code><br>│<br>▼<br><code>insmod rpmsg_tty.ko</code></p><p>Thus, once the RPMSG channel is created, the corresponding driver module can be automatically loaded without the user manually running modprobe.</p><blockquote><p>If user space wants to test manually:</p><p>View device uevent</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cat</span> /sys/bus/rpmsg/devices/virtio0.rpmsg-tty.-1.0/uevent</span><br><span class="line">BUS=rpmsg</span><br><span class="line">DRIVER=rpmsg_tty</span><br><span class="line">MODALIAS=rpmsg:rpmsg-tty</span><br></pre></td></tr></table></figure><p>Manually trigger uevent</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">echo</span> change &gt; /sys/bus/rpmsg/devices/virtio0.rpmsg-tty.-1.0/uevent</span><br></pre></td></tr></table></figure><p>This will re-invoke rpmsg_uevent(), and udev will process it again. View module alias</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ grep rpmsg /lib/modules/$(<span class="built_in">uname</span> -r)/modules.alias</span><br><span class="line"><span class="built_in">alias</span> rpmsg:* rpmsg_core</span><br><span class="line"><span class="built_in">alias</span> rpmsg:rpmsg-tty rpmsg_tty</span><br></pre></td></tr></table></figure></blockquote><h2 id="rpmsg-dev-groups">rpmsg_dev_groups</h2><p>dev_groups is the struct bus in the Linux device model_A field of type, its function is: automatically create a set of sysfs attribute files for each device registered on this bus.</p><p>In<code>rpmsg_core.c</code>:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">attribute</span> *<span class="title">rpmsg_dev_attrs</span>[] =</span> &#123;</span><br><span class="line">    &amp;dev_attr_name.attr,</span><br><span class="line">    &amp;dev_attr_modalias.attr,</span><br><span class="line">    &amp;dev_attr_dst.attr,</span><br><span class="line">    &amp;dev_attr_src.attr,</span><br><span class="line">    &amp;dev_attr_announce.attr,</span><br><span class="line">    &amp;dev_attr_driver_override.attr,</span><br><span class="line">    <span class="literal">NULL</span>,</span><br><span class="line">&#125;;</span><br><span class="line">ATTRIBUTE_GROUPS(rpmsg_dev);</span><br></pre></td></tr></table></figure><p>ATTRIBUTE_GROUPS(rpmsg_dev) is a kernel macro, which expands to:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">attribute_group</span> <span class="title">rpmsg_dev_group</span> =</span> &#123;</span><br><span class="line">    .attrs = rpmsg_dev_attrs,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">attribute_group</span> *<span class="title">rpmsg_dev_groups</span>[] =</span> &#123;</span><br><span class="line">    &amp;rpmsg_dev_group,</span><br><span class="line">    <span class="literal">NULL</span>,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Then attach to the bus:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">bus_type</span> <span class="title">rpmsg_bus</span> =</span> &#123;</span><br><span class="line">    .name       = <span class="string">&quot;rpmsg&quot;</span>,</span><br><span class="line">    .dev_groups = rpmsg_dev_groups,   <span class="comment">// ← Here</span></span><br><span class="line">    ...</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="Key-Data-Structure">Key Data Structure</h1><h2 id="struct-rpmsg-channel-info"><code>struct rpmsg_channel_info</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_channel_info - channel info representation</span></span><br><span class="line"><span class="comment"> * @name: name of service</span></span><br><span class="line"><span class="comment"> * @src: local address</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> &#123;</span></span><br><span class="line">    <span class="type">char</span> name[RPMSG_NAME_SIZE];   <span class="comment">// Service Name</span></span><br><span class="line">    u32 src;                       <span class="comment">// Local Address (Source Address)</span></span><br><span class="line">    u32 dst;                       <span class="comment">// Destination Address</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Common Scenarios:</p><ul><li><strong>Scenario 1: Pass channel information when creating an endpoint</strong></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// rpmsg_dev_In probe()</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span> =</span> &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">strncpy</span>(chinfo.name, rpdev-&gt;id.name, RPMSG_NAME_SIZE);  <span class="comment">// &quot;rpmsg-tty&quot;</span></span><br><span class="line">chinfo.src = rpdev-&gt;src;                                  <span class="comment">// Initial Address</span></span><br><span class="line">chinfo.dst = RPMSG_ADDR_ANY;                              <span class="comment">// Accept Any Remote</span></span><br><span class="line"></span><br><span class="line">ept = rpmsg_create_ept(rpdev, rpdrv-&gt;callback, <span class="literal">NULL</span>, chinfo);</span><br></pre></td></tr></table></figure><p>Here, chinfo tells the backend:</p><ul><li><p>What service I am:<code>name = &quot;rpmsg-tty&quot;</code></p></li><li><p>What local address I want: src (could be<code>RPMSG_ADDR_ANY</code>, let the backend assign)</p></li><li><p>Who I accept to access me:<code>dst = RPMSG_ADDR_ANY</code>(any remote)</p></li><li><p><strong>Scenario 2: Identifying a channel</strong></p></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// rpmsg_find_In device()</span></span><br><span class="line"><span class="keyword">struct</span> device *<span class="title function_">rpmsg_find_device</span><span class="params">(<span class="keyword">struct</span> device *parent,</span></span><br><span class="line"><span class="params">                                 <span class="keyword">struct</span> rpmsg_channel_info *chinfo)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> device_find_child(parent, chinfo, rpmsg_device_match);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// rpmsg_device_In match()</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_device_match</span><span class="params">(<span class="keyword">struct</span> device *dev, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> *<span class="title">chinfo</span> =</span> data;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> to_rpmsg_device(dev);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (chinfo-&gt;src != RPMSG_ADDR_ANY &amp;&amp; chinfo-&gt;src != rpdev-&gt;src)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> (chinfo-&gt;dst != RPMSG_ADDR_ANY &amp;&amp; chinfo-&gt;dst != rpdev-&gt;dst)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">strncmp</span>(chinfo-&gt;name, rpdev-&gt;id.name, RPMSG_NAME_SIZE))</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;  <span class="comment">// Match successful</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Here, chinfo is a “query condition”:</p><ul><li>You can use<code>name</code> + <code>src</code> + <code>dst</code>to precisely find an existing channel</li><li>You can also use<code>RPMSG_ADDR_ANY</code>as a wildcard to match by ignoring src or dst</li></ul><h2 id="struct-rpmsg-device"><code>struct rpmsg_device</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_device - device that belong to the rpmsg bus</span></span><br><span class="line"><span class="comment"> * @dev: the device struct</span></span><br><span class="line"><span class="comment"> * @id: device id (used to match between rpmsg drivers and devices)</span></span><br><span class="line"><span class="comment"> * @driver_override: driver name to force a match; do not set directly,</span></span><br><span class="line"><span class="comment"> *                   because core frees it; use driver_set_override() to</span></span><br><span class="line"><span class="comment"> *                   set or clear it.</span></span><br><span class="line"><span class="comment"> * @src: local address</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> * @ept: the rpmsg endpoint of this channel</span></span><br><span class="line"><span class="comment"> * @announce: if set, rpmsg will announce the creation/removal of this channel</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> <span class="title">dev</span>;</span>                  <span class="comment">// Base class of the Linux device model</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_id</span> <span class="title">id</span>;</span>          <span class="comment">// Device identifier (for matching)</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> *driver_override;        <span class="comment">// Force binding of a specific driver</span></span><br><span class="line">    u32 src;                            <span class="comment">// Local address</span></span><br><span class="line">    u32 dst;                            <span class="comment">// Destination address</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept</span>;</span>         <span class="comment">// Endpoint (receive callback bound here)</span></span><br><span class="line">    <span class="type">bool</span> announce;                      <span class="comment">// Whether to announce lifecycle to the remote side</span></span><br><span class="line">    <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_ops</span> *<span class="title">ops</span>;</span> <span class="comment">// Backend operation table</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ul><li><strong><code>struct device dev</code></strong></li></ul><p>This is the embedded base class of the Linux device model.<code>rpmsg_device</code>Access the kernel device model through composition rather than inheritance.</p><p>Key macro (in<code>rpmsg_internal.h</code>):</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev)</span></span><br></pre></td></tr></table></figure><p>The kernel bus callback only gets<code>struct device *</code>, converted via this macro to<code>struct rpmsg_device *</code>。</p><ul><li><strong><code>struct rpmsg_device_id id</code></strong></li></ul><p><code>include/linux/mod_devicetable.h</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* rpmsg */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_NAME_SIZE32</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_DEVICE_MODALIAS_FMT<span class="string">&quot;rpmsg:%s&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_id</span> &#123;</span></span><br><span class="line"><span class="type">char</span> name[RPMSG_NAME_SIZE];</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>This is the service name compared during bus matching. For example, “rpmsg-tty”, “rpmsg-client-sample”.</p><blockquote><p>Why wrap it in a separate struct?</p><ul><li>Following the Linux device model’s<code>mod_devicetable.h</code>standard<ul><li><code>MODULE_DEVICE_TABLE(rpmsg, ...) </code>requires a unified<code>xxx_device_id</code>format</li></ul></li><li>Allows future field expansion without breaking ABI</li></ul></blockquote><ul><li><code>const char *driver_override</code></li></ul><p>Forces a specific driver name. When set, the bus matching logic bypasses id_table and OF matching, directly comparing the driver name.</p><blockquote><p>Important: The comment says ‘do not set directly’ because the kernel will kfree() this pointer when the device is destroyed. Correct usage:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">driver_set_override(dev, &amp;rpdev-&gt;driver_override, <span class="string">&quot;my_drv&quot;</span>, <span class="built_in">strlen</span>(<span class="string">&quot;my_drv&quot;</span>));</span><br></pre></td></tr></table></figure></blockquote><ul><li><code>u32 src</code> / <code>u32 dst</code></li></ul><div class="table-wrap"><table><thead><tr><th><strong>Field</strong></th><th><strong>Meaning</strong></th><th><strong>Change Timing</strong></th></tr></thead><tbody><tr><td><strong>src</strong></td><td>Local address. When the device is created, it may be<code>RPMSG_ADDR_ANY</code>, updated to the actual value after backend allocation</td><td><code>rpmsg_dev_probe()</code>in<code>rpdev-&gt;src = ept-&gt;addr</code></td></tr><tr><td><strong>dst</strong></td><td>Peer address. Usually a known remote service address, or<code>RPMSG_ADDR_ANY</code></td><td>Set by the backend at creation time</td></tr></tbody></table></div><blockquote><p>src is the address I listen/receive on, dst is who I send to. rpmsg_device represents a logical channel, so it contains both end addresses.</p></blockquote><ul><li><code>struct rpmsg_endpoint *ept</code></li></ul><p>Points to the default endpoint of this channel. When the driver provides a callback,<code>rpmsg_dev_probe() </code>an endpoint is automatically created and assigned here.</p><blockquote><p>Note: An rpmsg_device can only have one default ept, but the driver can manually create additional endpoints in probe() (e.g., when multiple listening addresses are needed).</p></blockquote><ul><li><code>bool announce</code></li></ul><p>Controls whether to send to the remote end when the channel is created/destroyed**Name Service (NS)**announcement message.<code>announce = true</code>: sends “I’m online” on creation, “I’m offline” on destruction. The remote processor can update its service table or trigger corresponding client connections upon receipt.</p><ul><li><code>const struct rpmsg_device_ops *ops</code></li></ul><p>Backend operation table, defined in<code>rpmsg_internal.h</code>：</p> <figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_device_ops - indirection table for the rpmsg_device operations</span></span><br><span class="line"><span class="comment"> * @create_ept:create backend-specific endpoint, required</span></span><br><span class="line"><span class="comment"> * @announce_create:announce presence of new channel, optional</span></span><br><span class="line"><span class="comment"> * @announce_destroy:announce destruction of channel, optional</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Indirection table for the operations that a rpmsg backend should implement.</span></span><br><span class="line"><span class="comment"> * @announce_create and @announce_destroy are optional as the backend might</span></span><br><span class="line"><span class="comment"> * advertise new channels implicitly by creating the endpoints.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_ops</span> &#123;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *(*<span class="title">create_ept</span>)(<span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>,</span></span><br><span class="line"><span class="class">    <span class="title">rpmsg_rx_cb_t</span> <span class="title">cb</span>, <span class="title">void</span> *<span class="title">priv</span>,</span></span><br><span class="line"><span class="class">    <span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span>);</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> (*announce_create)(<span class="keyword">struct</span> rpmsg_device *ept);</span><br><span class="line"><span class="type">int</span> (*announce_destroy)(<span class="keyword">struct</span> rpmsg_device *ept);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>This is the boundary between the RPMSG core layer and the specific backend:</p><ul><li><code>rpmsg_core.c</code>only calls these interfaces</li><li><code>virtio_rpmsg_bus.c</code>(or other backends) implement these interfaces</li><li>Allows the RPMSG framework to support multiple underlying transports (though currently mainly virtio)</li></ul><h2 id="struct-rpmsg-endpoint"><code>struct rpmsg_endpoint</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="title function_">int</span> <span class="params">(*<span class="type">rpmsg_rx_cb_t</span>)</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *, <span class="type">void</span> *, <span class="type">int</span>, <span class="type">void</span> *, u32)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_endpoint - binds a local rpmsg address to its user</span></span><br><span class="line"><span class="comment"> * @rpdev: rpmsg channel device</span></span><br><span class="line"><span class="comment"> * @refcount: when this drops to zero, the ept is deallocated</span></span><br><span class="line"><span class="comment"> * @cb: rx callback handler</span></span><br><span class="line"><span class="comment"> * @cb_lock: must be taken before accessing/changing @cb</span></span><br><span class="line"><span class="comment"> * @addr: local rpmsg address</span></span><br><span class="line"><span class="comment"> * @priv: private data for the driver&#x27;s use</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as</span></span><br><span class="line"><span class="comment"> * it binds an rpmsg address with an rx callback handler.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Simple rpmsg drivers shouldn&#x27;t use this struct directly, because</span></span><br><span class="line"><span class="comment"> * things just work: every rpmsg driver provides an rx callback upon</span></span><br><span class="line"><span class="comment"> * registering to the bus, and that callback is then bound to its rpmsg</span></span><br><span class="line"><span class="comment"> * address when the driver is probed. When relevant inbound messages arrive</span></span><br><span class="line"><span class="comment"> * (i.e. messages which their dst address equals to the src address of</span></span><br><span class="line"><span class="comment"> * the rpmsg channel), the driver&#x27;s handler is invoked to process it.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * More complicated drivers though, that do need to allocate additional rpmsg</span></span><br><span class="line"><span class="comment"> * addresses, and bind them to different rx callbacks, must explicitly</span></span><br><span class="line"><span class="comment"> * create additional endpoints by themselves (see rpmsg_create_ept()).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> &#123;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kref</span> <span class="title">refcount</span>;</span></span><br><span class="line"><span class="type">rpmsg_rx_cb_t</span> cb;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">cb_lock</span>;</span></span><br><span class="line">u32 addr;</span><br><span class="line"><span class="type">void</span> *priv;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint_ops</span> *<span class="title">ops</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>endpoint is a first-class object for sending/receiving</strong></p><p>rpmsg core attaches all communication operations to<code>rpmsg_endpoint</code>instead of<code>rpmsg_device</code>. This means:</p><ul><li>A<code>rpmsg_device</code>(channel) can have multiple endpoints.</li><li>Different endpoints can have different callbacks and addresses.</li><li>Send operations are performed through endpoints, naturally carrying the source address.</li></ul><p>This is similar to the design of TCP sockets: the device is like a socket fd, and the endpoint is like a specific connection endpoint.</p><h3 id="rpmsg-rx-cb-tCallback-Types"><code>rpmsg_rx_cb_t</code>Callback Types</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="title function_">int</span> <span class="params">(*<span class="type">rpmsg_rx_cb_t</span>)</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *, <span class="type">void</span> *, <span class="type">int</span>, <span class="type">void</span> *, u32)</span>;</span><br></pre></td></tr></table></figure><p>Parameter Details</p><div class="table-wrap"><table><thead><tr><th><strong>Type</strong></th><th><strong>Meaning</strong></th></tr></thead><tbody><tr><td><code>struct rpmsg_device *</code></td><td>RPMSG device (channel) that received the message</td></tr><tr><td><code>void *</code></td><td>Message data pointer (payload)</td></tr><tr><td><code>int</code></td><td>Message length (payload len)</td></tr><tr><td><code>void *</code></td><td>private data (<code>rpmsg_create_ept</code>passed in when<code>priv</code>）</td></tr><tr><td><code>u32</code></td><td>sender address</td></tr></tbody></table></div><p>Usually returns 0 to indicate successful processing. The specific meaning is defined by the backend, generally:</p><ul><li>0: Message processed, buffer can be released</li><li>Negative value: processing error</li></ul><p><strong>Usage scenarios</strong></p><ul><li><strong>Scenario A: Simple driver, provide callback during registration</strong></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">my_rpmsg_cb</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev, <span class="type">void</span> *data, <span class="type">int</span> len,</span></span><br><span class="line"><span class="params">                       <span class="type">void</span> *priv, u32 src)</span></span><br><span class="line">&#123;</span><br><span class="line">    pr_info(<span class="string">&quot;received %d bytes from 0x%x: %.*s\n&quot;</span>, len, src, len, (<span class="type">char</span> *)data);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_driver</span> <span class="title">my_drv</span> =</span> &#123;</span><br><span class="line">    .drv.name = <span class="string">&quot;my_rpmsg&quot;</span>,</span><br><span class="line">    .id_table = my_id_table,</span><br><span class="line">    .probe    = my_probe,</span><br><span class="line">    .callback = my_rpmsg_cb,   <span class="comment">// ← Here</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>The framework<code>rpmsg_dev_probe()</code>automatically creates an endpoint when , calling the backend-implemented<code>rpdev-&gt;ops-&gt;create_ept()</code>to bind this callback (<code>virtio_rpmsg_bus.c</code>）。</p><ul><li><strong>Scenario B: Complex driver, manually create multiple endpoints</strong></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">my_probe</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span> =</span> &#123;&#125;;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept2</span>;</span></span><br><span class="line"><span class="comment">// Default endpoint already created by the framework (rpdev-&gt;ept)</span></span><br><span class="line">  <span class="comment">// Create an additional endpoint for control messages</span></span><br><span class="line">  <span class="built_in">strncpy</span>(chinfo.name, <span class="string">&quot;ctrl&quot;</span>, RPMSG_NAME_SIZE);</span><br><span class="line">  chinfo.src = RPMSG_ADDR_ANY;</span><br><span class="line"></span><br><span class="line">  ept2 = rpmsg_create_ept(rpdev, ctrl_msg_cb, my_priv, chinfo);</span><br><span class="line">  <span class="comment">// ctrl_msg_cb will receive messages sent to this new address</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="rpmsg-deviceandrpmsg-endpointrelationship"><code>rpmsg_device</code>and<code>rpmsg_endpoint</code>relationship</h3><p>This is key to understanding the RPMSG architecture:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">┌─────────────────────┐         ┌──────────────────────┐</span><br><span class="line">│  <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span>│         │ <span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span>│</span></span><br><span class="line"><span class="class">│  (代表一条通道)       │         │ (代表一个监听地址)      │</span></span><br><span class="line"><span class="class">├─────────────────────┤         ├──────────────────────┤</span></span><br><span class="line"><span class="class">│ <span class="title">dev</span>                 │◄──────────<span class="title">rpdev</span>                │</span></span><br><span class="line"><span class="class">│ <span class="title">id</span>.<span class="title">name</span> =</span> <span class="string">&quot;tty&quot;</span>     │         │ refcount             │</span><br><span class="line">│ src = <span class="number">0x401</span>         │         │ cb = my_callback     │</span><br><span class="line">│ dst = <span class="number">0x0</span>           │         │ addr = <span class="number">0x401</span>         │</span><br><span class="line">│ ept ─────────────────────────►│ priv                 │</span><br><span class="line">│ announce = <span class="literal">true</span>     │         │ ops                  │</span><br><span class="line">│ ops                 │         └──────────────────────┘</span><br><span class="line">└─────────────────────┘</span><br><span class="line">              │</span><br><span class="line">              │ <span class="number">1</span>:N</span><br><span class="line">              ▼</span><br><span class="line">        ┌──────────────┐</span><br><span class="line">        │ 额外的端点们   │  （驱动手动创建）</span><br><span class="line">        └──────────────┘</span><br></pre></td></tr></table></figure><p>Relationship summary:</p><ul><li>1<code>rpmsg_device</code>represents a logical channel (associated with a remote processor)</li><li>1<code>rpmsg_device</code>has at least 1 default<code>rpmsg_endpoint</code>（<code>rpdev-&gt;ept</code>）</li><li>1<code>rpmsg_device</code>can have N additional endpoints (manually created by the driver)</li><li>Each<code>rpmsg_endpoint</code>is bound to a unique<code>addr</code>, triggering its own cb when receiving messages sent to that address</li></ul><h3 id="Address-lifecycle-mapping">Address lifecycle mapping</h3><div class="table-wrap"><table><thead><tr><th><strong>Stage</strong></th><th><strong>rpmsg_device-&gt;src</strong></th><th><strong>rpmsg_endpoint-&gt;addr</strong></th><th><strong>Description</strong></th></tr></thead><tbody><tr><td><strong>Device just created</strong></td><td><code>RPMSG_ADDR_ANY</code></td><td>None (not yet created)</td><td>Waiting for backend allocation</td></tr><tr><td><strong><code>rpmsg_dev_probe()</code>In progress</strong></td><td>Updated, set to<code>ept-&gt;addr</code></td><td><code>ept-&gt;addr</code></td><td>Actual address allocated by backend</td></tr><tr><td><strong>Runtime</strong></td><td>Remains unchanged</td><td>Remains unchanged</td><td>Used for message routing</td></tr></tbody></table></div><p>Key assignment chain:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// rpmsg_dev_probe()</span></span><br><span class="line">ept = rpmsg_create_ept(rpdev, rpdrv-&gt;callback, <span class="literal">NULL</span>, chinfo);</span><br><span class="line">       │</span><br><span class="line">       └── 后端分配 addr（如 <span class="number">0x401</span>）</span><br><span class="line">              │</span><br><span class="line">              ▼</span><br><span class="line">rpdev-&gt;ept = ept;</span><br><span class="line">rpdev-&gt;src = ept-&gt;addr;   <span class="comment">// Synchronize to device structure!</span></span><br></pre></td></tr></table></figure><h2 id="struct-rpmsg-driver"><code>struct rpmsg_driver</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_driver - rpmsg driver struct</span></span><br><span class="line"><span class="comment"> * @drv: underlying device driver</span></span><br><span class="line"><span class="comment"> * @id_table: rpmsg ids serviced by this driver</span></span><br><span class="line"><span class="comment"> * @probe: invoked when a matching rpmsg channel (i.e. device) is found</span></span><br><span class="line"><span class="comment"> * @remove: invoked when the rpmsg channel is removed</span></span><br><span class="line"><span class="comment"> * @callback: invoked when an inbound message is received on the channel</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_driver</span> &#123;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">device_driver</span> <span class="title">drv</span>;</span></span><br><span class="line"><span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_id</span> *<span class="title">id_table</span>;</span></span><br><span class="line"><span class="type">int</span> (*probe)(<span class="keyword">struct</span> rpmsg_device *dev);</span><br><span class="line"><span class="type">void</span> (*remove)(<span class="keyword">struct</span> rpmsg_device *dev);</span><br><span class="line"><span class="type">int</span> (*callback)(<span class="keyword">struct</span> rpmsg_device *, <span class="type">void</span> *, <span class="type">int</span>, <span class="type">void</span> *, u32);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><code>struct rpmsg_driver</code>It is the core structure that driver developers need to fill in the RPMSG framework. It follows the Linux standard device driver model while encapsulating the RPMSG-specific message sending and receiving semantics.</p><ul><li><code>struct device_driver drv</code></li></ul><p>Linux device model base class, used to attach to<code>rpmsg_bus</code></p><ul><li><code>const struct rpmsg_device_id *id_table</code></li></ul><p>Device ID table supported by the driver (matched by service name)</p><ul><li><code>int (*probe)(struct rpmsg_device *)</code></li></ul><p>Called on successful match, executes driver initialization, refer to<code>rpmsg_dev_probe</code>function</p><ul><li><code>void (*remove)(struct rpmsg_device *dev);</code></li></ul><p>Called on device removal/driver unload, performs cleanup</p><ul><li><code>int (*callback)(struct rpmsg_device *, void *, int, void *, u32);</code></li></ul><p>Message reception callback (triggers automatic default endpoint creation by the framework),<code>callback</code>and<code>probe</code>division of labor</p><p><strong>callback triggers automatic endpoint creation</strong></p><div class="table-wrap"><table><thead><tr><th><strong>callback</strong></th><th><strong>Framework behavior</strong></th><th><strong>Applicable scenarios</strong></th></tr></thead><tbody><tr><td><strong>non-NULL</strong></td><td><code>rpmsg_dev_probe()</code>Automatically creates default endpoint, binds callback to<code>rpdev-&gt;src</code></td><td>Simple service, single address listening</td></tr><tr><td><strong>NULL</strong></td><td>Framework does not create default endpoint, driver must in<code>probe()</code>Manual call in<code>rpmsg_create_ept()</code></td><td>Complex service, multi-address, dynamic endpoint management</td></tr></tbody></table></div><p><strong>and<code>rpmsg_device</code> / <code>rpmsg_endpoint</code>triangular relationship</strong></p><div class="table-wrap"><table><thead><tr><th><strong>Object</strong></th><th><strong>Created by</strong></th><th><strong>Managed by</strong></th><th><strong>Lifecycle</strong></th></tr></thead><tbody><tr><td><strong><code>rpmsg_device</code></strong></td><td>Backend (virtio) receives NS message</td><td>Kernel device model</td><td>During channel existence</td></tr><tr><td><strong><code>rpmsg_endpoint</code></strong></td><td>Framework auto-creates (<code>rpdev-&gt;ept</code>) or driver manually creates</td><td><code>kref</code>Reference count</td><td>Bound to device or driver requirements</td></tr><tr><td><strong><code>rpmsg_driver</code></strong></td><td>Static definition by driver author</td><td><code>module_init</code> / <code>module_exit</code></td><td>During module loading</td></tr></tbody></table></div><p><strong>Call chain</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">rpmsg_bus.match() 比较</span><br><span class="line">  rpdev-&gt;id.name  vs  rpdrv-&gt;id_table[].name</span><br><span class="line">        ↓ 匹配成功</span><br><span class="line">rpmsg_bus.probe()</span><br><span class="line">  ├── dev_pm_domain_attach()</span><br><span class="line">  ├── rpmsg_create_ept()  ← virtio_rpmsg_bus.c 中赋值 ept-&gt;cb = rpdrv-&gt;callback</span><br><span class="line">  ├── rpdrv-&gt;probe()      ← 驱动初始化</span><br><span class="line">  └── announce_create()</span><br><span class="line">        ↓ 远端发消息</span><br><span class="line">rpdev-&gt;ops-&gt;announce_create() ← virtio_rpmsg_bus.c 中调用ept-&gt;cb</span><br></pre></td></tr></table></figure><h2 id="struct-rpmsg-device-ops"><code>struct rpmsg_device_ops</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_device_ops - indirection table for the rpmsg_device operations</span></span><br><span class="line"><span class="comment"> * @create_ept:create backend-specific endpoint, required</span></span><br><span class="line"><span class="comment"> * @announce_create:announce presence of new channel, optional</span></span><br><span class="line"><span class="comment"> * @announce_destroy:announce destruction of channel, optional</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Indirection table for the operations that a rpmsg backend should implement.</span></span><br><span class="line"><span class="comment"> * @announce_create and @announce_destroy are optional as the backend might</span></span><br><span class="line"><span class="comment"> * advertise new channels implicitly by creating the endpoints.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_ops</span> &#123;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *(*<span class="title">create_ept</span>)(<span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>,</span></span><br><span class="line"><span class="class">    <span class="title">rpmsg_rx_cb_t</span> <span class="title">cb</span>, <span class="title">void</span> *<span class="title">priv</span>,</span></span><br><span class="line"><span class="class">    <span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span>);</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> (*announce_create)(<span class="keyword">struct</span> rpmsg_device *ept);</span><br><span class="line"><span class="type">int</span> (*announce_destroy)(<span class="keyword">struct</span> rpmsg_device *ept);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="Call-timing">Call timing</h3><div class="table-wrap"><table><thead><tr><th><strong>Member</strong></th><th><strong>Required</strong></th><th><strong>Call function</strong></th><th><strong>Call timing</strong></th><th><strong>Precondition</strong></th></tr></thead><tbody><tr><td><strong>create_ept</strong></td><td>Required</td><td><code>rpmsg_create_ept()</code></td><td>① Framework automatically creates default endpoints;<br />② Driver manually creates endpoints</td><td><code>rpdev-&gt;ops</code>Non-empty</td></tr><tr><td><strong>announce_create</strong></td><td>Optional</td><td><code>rpmsg_dev_probe()</code></td><td>Driver<code>probe()</code>After success</td><td>ept created successfully and<code>ops-&gt;announce_create</code>non-empty</td></tr><tr><td><strong>announce_destroy</strong></td><td>optional</td><td><code>rpmsg_dev_remove()</code></td><td>At the very beginning of device removal/driver unload</td><td><code>ops-&gt;announce_destroy</code>non-empty</td></tr></tbody></table></div><hr><h4 id="rpdev-ops-create-ept"><code>rpdev-&gt;ops-&gt;create_ept()</code></h4><ul><li>Framework auto-creates<code>rpmsg_core.c</code> : <code>rpmsg_dev_probe()</code></li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// rpmsg_core.c: rpmsg_dev_probe()</span></span><br><span class="line"><span class="keyword">if</span> (rpdrv-&gt;callback) &#123;</span><br><span class="line">    ept = rpmsg_create_ept(rpdev, rpdrv-&gt;callback, <span class="literal">NULL</span>, chinfo);</span><br><span class="line">    <span class="comment">// Internal call: rpdev-&gt;ops-&gt;create_ept(rpdev, cb, priv, chinfo)</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>Driver manually creates</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Driver code example</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">my_probe</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept2</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span> =</span> &#123;</span><br><span class="line">        .name = <span class="string">&quot;ctrl&quot;</span>,</span><br><span class="line">        .src = RPMSG_ADDR_ANY,</span><br><span class="line">        .dst = RPMSG_ADDR_ANY,</span><br><span class="line">    &#125;;</span><br><span class="line">    ept2 = rpmsg_create_ept(rpdev, ctrl_cb, my_priv_data, chinfo);</span><br><span class="line">  <span class="comment">// Internal call: rpdev-&gt;ops-&gt;create_ept(rpdev, ctrl_cb, my_priv_data, chinfo)</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="rpdev-ops-announce-create"><code>rpdev-&gt;ops-&gt;announce_create()</code></h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// rpmsg_core.c: rpmsg_dev_probe()</span></span><br><span class="line">err = rpdrv-&gt;probe(rpdev);          <span class="comment">// ← ① First let the driver complete initialization</span></span><br><span class="line"><span class="keyword">if</span> (err)</span><br><span class="line">    <span class="keyword">goto</span> destroy_ept;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (ept &amp;&amp; rpdev-&gt;ops-&gt;announce_create) &#123;   <span class="comment">// ← ② Announce after driver is ready</span></span><br><span class="line">    err = rpdev-&gt;ops-&gt;announce_create(rpdev);</span><br><span class="line">    <span class="keyword">if</span> (err)</span><br><span class="line">        <span class="keyword">goto</span> remove_rpdev;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Backend:</p><ul><li>Send a “channel creation” message to the remote processor via the RPMSG Name Service protocol</li><li>The message content usually includes: service name<code>rpdev-&gt;id.name</code>, local address<code>rpdev-&gt;src</code></li></ul><hr><h4 id="rpdev-ops-announce-destroy"><code>rpdev-&gt;ops-&gt;announce_destroy()</code></h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// rpmsg_core.c: rpmsg_dev_remove()</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_dev_remove</span><span class="params">(<span class="keyword">struct</span> device *dev)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> to_rpmsg_device(dev);</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_driver</span> *<span class="title">rpdrv</span> =</span> to_rpmsg_driver(rpdev-&gt;dev.driver);</span><br><span class="line">    <span class="type">int</span> err = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (rpdev-&gt;ops-&gt;announce_destroy)       <span class="comment">// ← ① First executed: notify the remote end</span></span><br><span class="line">        err = rpdev-&gt;ops-&gt;announce_destroy(rpdev);</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">if</span> (rpdrv-&gt;remove)                      <span class="comment">// ← ② Then call driver cleanup</span></span><br><span class="line">        rpdrv-&gt;remove(rpdev);</span><br><span class="line">  </span><br><span class="line">    dev_pm_domain_detach(dev, <span class="literal">true</span>);        <span class="comment">// ← ③ Power separation</span></span><br><span class="line">  </span><br><span class="line">    <span class="keyword">if</span> (rpdev-&gt;ept)</span><br><span class="line">        rpmsg_destroy_ept(rpdev-&gt;ept);      <span class="comment">// ← ④ Finally destroy the endpoint</span></span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> err;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Backend:</p><ul><li>Send a “channel destruction” message to the remote end via the name service protocol</li><li>After receiving it, the remote end will delete the channel from its own service table; subsequent messages sent to that address will be discarded or return an error</li></ul><h3 id="Summary">Summary</h3><div class="table-wrap"><table><thead><tr><th><strong>Operation</strong></th><th><strong>Caller</strong></th><th><strong>Callee</strong></th><th><strong>Core semantics</strong></th></tr></thead><tbody><tr><td><strong>create_ept</strong></td><td><code>rpmsg_create_ept()</code></td><td>Backend</td><td>Allocate resources: bind backend buffer and interrupt to local address</td></tr><tr><td><strong>announce_create</strong></td><td><code>rpmsg_dev_probe()</code></td><td>Backend</td><td>Publish service: notify remote that “this address has a service listening”</td></tr><tr><td><strong>announce_destroy</strong></td><td><code>rpmsg_dev_remove()</code></td><td>Backend</td><td>Revoke service: notify remote that “the service at this address is about to stop”</td></tr></tbody></table></div><p>These three hooks together implement the complete lifecycle management of RPMSG “create-publish-revoke”, serving as the most critical contract interface between the core layer and the backend</p><h2 id="struct-rpmsg-endpoint-ops"><code>struct rpmsg_endpoint_ops</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_endpoint_ops - indirection table for rpmsg_endpoint operations</span></span><br><span class="line"><span class="comment"> * @destroy_ept:see @rpmsg_destroy_ept(), required</span></span><br><span class="line"><span class="comment"> * @send:see @rpmsg_send(), required</span></span><br><span class="line"><span class="comment"> * @sendto:see @rpmsg_sendto(), optional</span></span><br><span class="line"><span class="comment"> * @send_offchannel:see @rpmsg_send_offchannel(), optional</span></span><br><span class="line"><span class="comment"> * @trysend:see @rpmsg_trysend(), required</span></span><br><span class="line"><span class="comment"> * @trysendto:see @rpmsg_trysendto(), optional</span></span><br><span class="line"><span class="comment"> * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional</span></span><br><span class="line"><span class="comment"> * @poll:see @rpmsg_poll(), optional</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Indirection table for the operations that a rpmsg backend should implement.</span></span><br><span class="line"><span class="comment"> * In addition to @destroy_ept, the backend must at least implement @send and</span></span><br><span class="line"><span class="comment"> * @trysend, while the variants sending data off-channel are optional.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint_ops</span> &#123;</span></span><br><span class="line"><span class="type">void</span> (*destroy_ept)(<span class="keyword">struct</span> rpmsg_endpoint *ept);</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> (*send)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len);</span><br><span class="line"><span class="type">int</span> (*sendto)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len, u32 dst);</span><br><span class="line"><span class="type">int</span> (*send_offchannel)(<span class="keyword">struct</span> rpmsg_endpoint *ept, u32 src, u32 dst,</span><br><span class="line">  <span class="type">void</span> *data, <span class="type">int</span> len);</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> (*trysend)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len);</span><br><span class="line"><span class="type">int</span> (*trysendto)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len, u32 dst);</span><br><span class="line"><span class="type">int</span> (*trysend_offchannel)(<span class="keyword">struct</span> rpmsg_endpoint *ept, u32 src, u32 dst,</span><br><span class="line">     <span class="type">void</span> *data, <span class="type">int</span> len);</span><br><span class="line"><span class="type">__poll_t</span> (*poll)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="keyword">struct</span> file *filp,</span><br><span class="line">     poll_table *wait);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="Decoupling-of-rpmsg-core-and-backend"><strong>Decoupling of rpmsg core and backend</strong></h3><p>The architecture of the rpmsg subsystem can be viewed as two layers:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">+---------------------------------------------------+</span><br><span class="line">|  rpmsg client driver (user code)                  |</span><br><span class="line">|    - imx_rproc, ti_pruss, etc.                    |</span><br><span class="line">|    - rpmsg_send(), rpmsg_create_ept(), ...        |</span><br><span class="line">+---------------------------------------------------+</span><br><span class="line">|  rpmsg core (drivers/rpmsg/rpmsg_core.c)          |</span><br><span class="line">|    - 提供 EXPORT_SYMBOL 的 API                     |</span><br><span class="line">|    - 通过 ops 表转发到 backend                      |</span><br><span class="line">+---------------------------------------------------+</span><br><span class="line">|  rpmsg transport backend                          |</span><br><span class="line">|    - virtio_rpmsg_bus.c  (virtio 传输)             |</span><br><span class="line">|    - 未来可能有其他 backend                         |</span><br><span class="line">|    - 实现 rpmsg_endpoint_ops / rpmsg_device_ops    |</span><br><span class="line">+---------------------------------------------------</span><br></pre></td></tr></table></figure><div class="table-wrap"><table><thead><tr><th><strong>Layer</strong></th><th><strong>ops</strong></th><th><strong>Operation object</strong></th><th><strong>Typical operation</strong></th></tr></thead><tbody><tr><td><strong>Rpmsg Device</strong></td><td><code>rpmsg_device_ops</code></td><td><code>rpmsg_device</code> (channel)</td><td>Create endpoint, announce channel existence</td></tr><tr><td><strong>Rpmsg Endpoint</strong></td><td><code>rpmsg_endpoint_ops</code></td><td><code>rpmsg_endpoint</code>(communication endpoint)</td><td>Send data, destroy endpoint, poll</td></tr></tbody></table></div><p>This layering allows the core to perform name service announcement during device registration (via rpmsg_device_ops.announce_create), while the actual data transmission goes through the endpoint (via rpmsg_endpoint_ops.send）。</p><p>Hierarchical relationship:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">rpmsg_device (代表一个 channel)</span><br><span class="line">    |</span><br><span class="line">    |-- rpmsg_device_ops</span><br><span class="line">    |       |</span><br><span class="line">    |       |-- create_ept() --&gt; rpmsg_endpoint</span><br><span class="line">    |       |-- announce_create/destroy()</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line"><span class="title function_">rpmsg_endpoint</span> <span class="params">(代表 channel 上的一个通信端点)</span></span><br><span class="line">    |</span><br><span class="line">    |-- rpmsg_endpoint_ops</span><br><span class="line">    |       |</span><br><span class="line">    |       |-- send/sendto/send_offchannel</span><br><span class="line">    |       |-- trysend/trysendto/trysend_offchannel</span><br><span class="line">    |       |-- destroy_ept</span><br><span class="line">    |       |-- poll</span><br></pre></td></tr></table></figure><h3 id=""></h3><h3 id="Forwarding-logic-of-rpmsg-core"><strong>Forwarding logic of rpmsg core</strong></h3><p><code>drivers/rpmsg/rpmsg_core.c</code>Each API in it is a thin layer of encapsulation, taking a few typical functions as examples:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">rpmsg_send</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len)</span></span><br><span class="line">&#123;</span><br><span class="line">      <span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line">              <span class="keyword">return</span> -EINVAL;</span><br><span class="line">      <span class="keyword">if</span> (!ept-&gt;ops-&gt;send)</span><br><span class="line">              <span class="keyword">return</span> -ENXIO;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">return</span> ept-&gt;ops-&gt;send(ept, data, len);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Because send is required, the core has no fallback. If XIO.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">rpmsg_sendto</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len, u32 dst)</span></span><br><span class="line">&#123;</span><br><span class="line">      <span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line">              <span class="keyword">return</span> -EINVAL;</span><br><span class="line">      <span class="keyword">if</span> (!ept-&gt;ops-&gt;sendto)</span><br><span class="line">              <span class="keyword">return</span> -ENXIO;                                                                                                               </span><br><span class="line">      <span class="keyword">return</span> ept-&gt;ops-&gt;sendto(ept, data, len, dst);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>See<code>rpmsg_core.c</code>Although the comment says sendto is optional, the semantics of optional are “the backend can choose not to support this operation,” not “the core will handle compatibility for you.” If a backend only implements send and trysend, calling sendto will fail.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">__poll_t</span> <span class="title function_">rpmsg_poll</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="keyword">struct</span> file *filp,</span></span><br><span class="line"><span class="params">                  poll_table *wait)</span> &#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> (!ept-&gt;ops-&gt;poll)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ept-&gt;ops-&gt;poll(ept, filp, wait);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>virtio_rpmsg_bus.c</code>does not implement poll, so through<code>rpmsg_poll()</code>returns 0 when called. And<code>drivers/rpmsg/rpmsg_char.c</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mask |= rpmsg_poll(eptdev-&gt;ept, filp, wait);</span><br></pre></td></tr></table></figure><p><code>rpmsg_char.c</code>provides user-space<code>/dev/rpmsgX</code>interface.<code>rpmsg_poll()</code>The result is ORed into<code>poll mask</code>If the backend does not implement poll, user-space operations on<code>/dev/rpmsgX</code>doing<code>poll()</code>can only detect read events (EPOLLIN), and cannot through<code>rpmsg_poll()</code>Check the write-ready status. However, due to virtio’s<code>rpmsg_send</code>series either blocking or returning immediately, the write path does not actually rely on poll.</p><h3 id="Summary-2">Summary</h3><div class="table-wrap"><table><thead><tr><th><strong>ops</strong></th><th><strong>required</strong></th><th><strong>Core behavior (when not implemented)</strong></th><th><strong>virtio backend</strong></th></tr></thead><tbody><tr><td><strong>destroy_ept</strong></td><td>✅ required</td><td>N/A (will not be NULL, must be set during initialization)</td><td><code>virtio_rpmsg_destroy_ept</code></td></tr><tr><td><strong>send</strong></td><td>✅ required</td><td><code>-ENXIO</code></td><td><code>virtio_rpmsg_send</code></td></tr><tr><td><strong>trysend</strong></td><td>✅ required</td><td><code>-ENXIO</code></td><td><code>virtio_rpmsg_trysend</code></td></tr><tr><td><strong>sendto</strong></td><td>optional</td><td><code>-ENXIO</code></td><td><code>virtio_rpmsg_sendto</code></td></tr><tr><td><strong>send_offchannel</strong></td><td>optional</td><td><code>-ENXIO</code></td><td><code>virtio_rpmsg_send_offchannel</code></td></tr><tr><td><strong>trysendto</strong></td><td>optional</td><td><code>-ENXIO</code></td><td><code>virtio_rpmsg_trysendto</code></td></tr><tr><td><strong>trysend_offchannel</strong></td><td>optional</td><td><code>-ENXIO</code></td><td><code>virtio_rpmsg_trysend_offchannel</code></td></tr><tr><td><strong>poll</strong></td><td>optional</td><td>Returns 0</td><td><em>Undefined</em></td></tr></tbody></table></div><h1 id="EXPORT-SYMBOLS">EXPORT_SYMBOLS</h1><h2 id="rpmsg-create-ept"><code>rpmsg_create_ept()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_create_ept() - create a new rpmsg_endpoint</span></span><br><span class="line"><span class="comment"> * @rpdev: rpmsg channel device</span></span><br><span class="line"><span class="comment"> * @cb: rx callback handler</span></span><br><span class="line"><span class="comment"> * @priv: private data for the driver&#x27;s use</span></span><br><span class="line"><span class="comment"> * @chinfo: channel_info with the local rpmsg address to bind with @cb</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Every rpmsg address in the system is bound to an rx callback (so when</span></span><br><span class="line"><span class="comment"> * inbound messages arrive, they are dispatched by the rpmsg bus using the</span></span><br><span class="line"><span class="comment"> * appropriate callback handler) by means of an rpmsg_endpoint struct.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function allows drivers to create such an endpoint, and by that,</span></span><br><span class="line"><span class="comment"> * bind a callback, and possibly some private data too, to an rpmsg address</span></span><br><span class="line"><span class="comment"> * (either one that is known in advance, or one that will be dynamically</span></span><br><span class="line"><span class="comment"> * assigned for them).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint</span></span><br><span class="line"><span class="comment"> * is already created for them when they are probed by the rpmsg bus</span></span><br><span class="line"><span class="comment"> * (using the rx callback provided when they registered to the rpmsg bus).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * So things should just work for simple drivers: they already have an</span></span><br><span class="line"><span class="comment"> * endpoint, their rx callback is bound to their rpmsg address, and when</span></span><br><span class="line"><span class="comment"> * relevant inbound messages arrive (i.e. messages which their dst address</span></span><br><span class="line"><span class="comment"> * equals to the src address of their rpmsg channel), the driver&#x27;s handler</span></span><br><span class="line"><span class="comment"> * is invoked to process it.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * That said, more complicated drivers might need to allocate</span></span><br><span class="line"><span class="comment"> * additional rpmsg addresses, and bind them to different rx callbacks.</span></span><br><span class="line"><span class="comment"> * To accomplish that, those drivers need to call this function.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Drivers should provide their @rpdev channel (so the new endpoint would belong</span></span><br><span class="line"><span class="comment"> * to the same remote processor their channel belongs to), an rx callback</span></span><br><span class="line"><span class="comment"> * function, an optional private data (which is provided back when the</span></span><br><span class="line"><span class="comment"> * rx callback is invoked), and an address they want to bind with the</span></span><br><span class="line"><span class="comment"> * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will</span></span><br><span class="line"><span class="comment"> * dynamically assign them an available rpmsg address (drivers should have</span></span><br><span class="line"><span class="comment"> * a very good reason why not to always use RPMSG_ADDR_ANY here).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns a pointer to the endpoint on success, or NULL on error.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">struct</span> rpmsg_endpoint *<span class="title function_">rpmsg_create_ept</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev,</span></span><br><span class="line"><span class="params"><span class="type">rpmsg_rx_cb_t</span> cb, <span class="type">void</span> *priv,</span></span><br><span class="line"><span class="params"><span class="keyword">struct</span> rpmsg_channel_info chinfo)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!rpdev))</span><br><span class="line"><span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> rpdev-&gt;ops-&gt;create_ept(rpdev, cb, priv, chinfo);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_create_ept);</span><br></pre></td></tr></table></figure><p>Call<code>rpdev-&gt;ops</code>in<code>create_ept</code></p><h2 id="rpmsg-destroy-ept"><code>rpmsg_destroy_ept()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @ept: endpoing to destroy</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Should be used by drivers to destroy an rpmsg endpoint previously</span></span><br><span class="line"><span class="comment"> * created with rpmsg_create_ept(). As with other types of &quot;free&quot; NULL</span></span><br><span class="line"><span class="comment"> * is a valid parameter.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">rpmsg_destroy_ept</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (ept &amp;&amp; ept-&gt;ops)</span><br><span class="line">ept-&gt;ops-&gt;destroy_ept(ept);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_destroy_ept);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-send"><code>rpmsg_send()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_send() - send a message across to the remote processor</span></span><br><span class="line"><span class="comment"> * @ept: the rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @data: payload of message</span></span><br><span class="line"><span class="comment"> * @len: length of payload</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function sends @data of length @len on the @ept endpoint.</span></span><br><span class="line"><span class="comment"> * The message will be sent to the remote processor which the @ept</span></span><br><span class="line"><span class="comment"> * endpoint belongs to, using @ept&#x27;s address and its associated rpmsg</span></span><br><span class="line"><span class="comment"> * device destination addresses.</span></span><br><span class="line"><span class="comment"> * In case there are no TX buffers available, the function will block until</span></span><br><span class="line"><span class="comment"> * one becomes available, or a timeout of 15 seconds elapses. When the latter</span></span><br><span class="line"><span class="comment"> * happens, -ERESTARTSYS is returned.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Can only be called from process context (for now).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 on success and an appropriate error value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">rpmsg_send</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"><span class="keyword">if</span> (!ept-&gt;ops-&gt;send)</span><br><span class="line"><span class="keyword">return</span> -ENXIO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ept-&gt;ops-&gt;send(ept, data, len);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_send);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-sendto"><code>rpmsg_sendto()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_sendto() - send a message across to the remote processor, specify dst</span></span><br><span class="line"><span class="comment"> * @ept: the rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @data: payload of message</span></span><br><span class="line"><span class="comment"> * @len: length of payload</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function sends @data of length @len to the remote @dst address.</span></span><br><span class="line"><span class="comment"> * The message will be sent to the remote processor which the @ept</span></span><br><span class="line"><span class="comment"> * endpoint belongs to, using @ept&#x27;s address as source.</span></span><br><span class="line"><span class="comment"> * In case there are no TX buffers available, the function will block until</span></span><br><span class="line"><span class="comment"> * one becomes available, or a timeout of 15 seconds elapses. When the latter</span></span><br><span class="line"><span class="comment"> * happens, -ERESTARTSYS is returned.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Can only be called from process context (for now).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 on success and an appropriate error value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">rpmsg_sendto</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len, u32 dst)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"><span class="keyword">if</span> (!ept-&gt;ops-&gt;sendto)</span><br><span class="line"><span class="keyword">return</span> -ENXIO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ept-&gt;ops-&gt;sendto(ept, data, len, dst);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_sendto);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-send-offchannel"><code>rpmsg_send_offchannel</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_send_offchannel() - send a message using explicit src/dst addresses</span></span><br><span class="line"><span class="comment"> * @ept: the rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @src: source address</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> * @data: payload of message</span></span><br><span class="line"><span class="comment"> * @len: length of payload</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function sends @data of length @len to the remote @dst address,</span></span><br><span class="line"><span class="comment"> * and uses @src as the source address.</span></span><br><span class="line"><span class="comment"> * The message will be sent to the remote processor which the @ept</span></span><br><span class="line"><span class="comment"> * endpoint belongs to.</span></span><br><span class="line"><span class="comment"> * In case there are no TX buffers available, the function will block until</span></span><br><span class="line"><span class="comment"> * one becomes available, or a timeout of 15 seconds elapses. When the latter</span></span><br><span class="line"><span class="comment"> * happens, -ERESTARTSYS is returned.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Can only be called from process context (for now).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 on success and an appropriate error value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">rpmsg_send_offchannel</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, u32 src, u32 dst,</span></span><br><span class="line"><span class="params">  <span class="type">void</span> *data, <span class="type">int</span> len)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"><span class="keyword">if</span> (!ept-&gt;ops-&gt;send_offchannel)</span><br><span class="line"><span class="keyword">return</span> -ENXIO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ept-&gt;ops-&gt;send_offchannel(ept, src, dst, data, len);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_send_offchannel);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-trysend"><code>rpmsg_trysend()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_trysend() - send a message across to the remote processor</span></span><br><span class="line"><span class="comment"> * @ept: the rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @data: payload of message</span></span><br><span class="line"><span class="comment"> * @len: length of payload</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function sends @data of length @len on the @ept endpoint.</span></span><br><span class="line"><span class="comment"> * The message will be sent to the remote processor which the @ept</span></span><br><span class="line"><span class="comment"> * endpoint belongs to, using @ept&#x27;s address as source and its associated</span></span><br><span class="line"><span class="comment"> * rpdev&#x27;s address as destination.</span></span><br><span class="line"><span class="comment"> * In case there are no TX buffers available, the function will immediately</span></span><br><span class="line"><span class="comment"> * return -ENOMEM without waiting until one becomes available.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Can only be called from process context (for now).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 on success and an appropriate error value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">rpmsg_trysend</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"><span class="keyword">if</span> (!ept-&gt;ops-&gt;trysend)</span><br><span class="line"><span class="keyword">return</span> -ENXIO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ept-&gt;ops-&gt;trysend(ept, data, len);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_trysend);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-trysendto"><code>rpmsg_trysendto()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_trysendto() - send a message across to the remote processor, specify dst</span></span><br><span class="line"><span class="comment"> * @ept: the rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @data: payload of message</span></span><br><span class="line"><span class="comment"> * @len: length of payload</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function sends @data of length @len to the remote @dst address.</span></span><br><span class="line"><span class="comment"> * The message will be sent to the remote processor which the @ept</span></span><br><span class="line"><span class="comment"> * endpoint belongs to, using @ept&#x27;s address as source.</span></span><br><span class="line"><span class="comment"> * In case there are no TX buffers available, the function will immediately</span></span><br><span class="line"><span class="comment"> * return -ENOMEM without waiting until one becomes available.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Can only be called from process context (for now).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 on success and an appropriate error value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">rpmsg_trysendto</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len, u32 dst)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"><span class="keyword">if</span> (!ept-&gt;ops-&gt;trysendto)</span><br><span class="line"><span class="keyword">return</span> -ENXIO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ept-&gt;ops-&gt;trysendto(ept, data, len, dst);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_trysendto);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-poll"><code>rpmsg_poll()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_poll() - poll the endpoint&#x27;s send buffers</span></span><br><span class="line"><span class="comment"> * @ept:the rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @filp:file for poll_wait()</span></span><br><span class="line"><span class="comment"> * @wait:poll_table for poll_wait()</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns mask representing the current state of the endpoint&#x27;s send buffers</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">__poll_t</span> <span class="title function_">rpmsg_poll</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="keyword">struct</span> file *filp,</span></span><br><span class="line"><span class="params">poll_table *wait)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span> (!ept-&gt;ops-&gt;poll)</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ept-&gt;ops-&gt;poll(ept, filp, wait);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_poll);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-trysend-offchannel"><code>rpmsg_trysend_offchannel()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses</span></span><br><span class="line"><span class="comment"> * @ept: the rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @src: source address</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> * @data: payload of message</span></span><br><span class="line"><span class="comment"> * @len: length of payload</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function sends @data of length @len to the remote @dst address,</span></span><br><span class="line"><span class="comment"> * and uses @src as the source address.</span></span><br><span class="line"><span class="comment"> * The message will be sent to the remote processor which the @ept</span></span><br><span class="line"><span class="comment"> * endpoint belongs to.</span></span><br><span class="line"><span class="comment"> * In case there are no TX buffers available, the function will immediately</span></span><br><span class="line"><span class="comment"> * return -ENOMEM without waiting until one becomes available.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Can only be called from process context (for now).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 on success and an appropriate error value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">rpmsg_trysend_offchannel</span><span class="params">(<span class="keyword">struct</span> rpmsg_endpoint *ept, u32 src, u32 dst,</span></span><br><span class="line"><span class="params">     <span class="type">void</span> *data, <span class="type">int</span> len)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (WARN_ON(!ept))</span><br><span class="line"><span class="keyword">return</span> -EINVAL;</span><br><span class="line"><span class="keyword">if</span> (!ept-&gt;ops-&gt;trysend_offchannel)</span><br><span class="line"><span class="keyword">return</span> -ENXIO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> ept-&gt;ops-&gt;trysend_offchannel(ept, src, dst, data, len);</span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_trysend_offchannel);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-find-device"><code>rpmsg_find_device()</code></h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * match a rpmsg channel with a channel info struct.</span></span><br><span class="line"><span class="comment"> * this is used to make sure we&#x27;re not creating rpmsg devices for channels</span></span><br><span class="line"><span class="comment"> * that already exist.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_device_match</span><span class="params">(<span class="keyword">struct</span> device *dev, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> *<span class="title">chinfo</span> =</span> data;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span> =</span> to_rpmsg_device(dev);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (chinfo-&gt;src != RPMSG_ADDR_ANY &amp;&amp; chinfo-&gt;src != rpdev-&gt;src)</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (chinfo-&gt;dst != RPMSG_ADDR_ANY &amp;&amp; chinfo-&gt;dst != rpdev-&gt;dst)</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">strncmp</span>(chinfo-&gt;name, rpdev-&gt;id.name, RPMSG_NAME_SIZE))</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* found a match ! */</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> device *<span class="title function_">rpmsg_find_device</span><span class="params">(<span class="keyword">struct</span> device *parent,</span></span><br><span class="line"><span class="params"> <span class="keyword">struct</span> rpmsg_channel_info *chinfo)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">return</span> device_find_child(parent, chinfo, rpmsg_device_match);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line">EXPORT_SYMBOL(rpmsg_find_device);</span><br></pre></td></tr></table></figure><h1 id="Complete-flowchart">Complete flowchart</h1><blockquote><p>Click the code block to expand</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line">local processors                                 remote processor</span><br><span class="line"> │ [dtb] virtio_device match virtio_driver            │[dtb] virtio_device match virtio_driver</span><br><span class="line"> │ rpmsg_probe (virtio_rpmsg_bus.c)                   │rpmsg_probe (virtio_rpmsg_bus.c)  </span><br><span class="line"> │ vrp-&gt;ns_ept = __rpmsg_create_ept(vrp, <span class="literal">NULL</span>,        │vrp-&gt;ns_ept = __rpmsg_create_ept(vrp, <span class="literal">NULL</span>,</span><br><span class="line"> │     rpmsg_ns_cb, vrp, RPMSG_NS_ADDR);              │     rpmsg_ns_cb, vrp, RPMSG_NS_ADDR);</span><br><span class="line"> │                                                    │</span><br><span class="line"> │                                                    │</span><br><span class="line"> │                                                    │</span><br><span class="line"> │ [dtb] rpmsg_device <span class="keyword">register</span> rpmsg_bus              │[dtb] rpmsg_device <span class="keyword">register</span> rpmsg_bus</span><br><span class="line"> │ rpmsg_dev_probe(rpdev-&gt;dev) (rpmsg_core.c)         │rpmsg_dev_probe(rpdev-&gt;dev) (rpmsg_core.c)</span><br><span class="line"> │   rpdrv-&gt;callback = <span class="literal">NULL</span>, don<span class="string">&#x27;t create ept         │  rpdrv-&gt;callback = NULL, don&#x27;</span>t create ept</span><br><span class="line"> │   rpdrv-&gt;probe = rpmsg_chrdev_probe (rpmsg_char.c) │  rpdrv-&gt;probe = rpmsg_chrdev_probe (rpmsg_char.c)</span><br><span class="line"> │      create cdev <span class="string">&quot;rpmsg_ctrl0&quot;</span>                     │     create cdev <span class="string">&quot;rpmsg_ctrl0&quot;</span></span><br><span class="line"> │  n rpdev-&gt;ops-&gt;announce_create(rpdev);             │  rpdev-&gt;ops-&gt;announce_create(rpdev);</span><br><span class="line"> │      = virtio_rpmsg_announce_create(rpdev)         │     = virtio_rpmsg_announce_create(rpdev)</span><br><span class="line"> │          rpdev-&gt;ept = <span class="literal">NULL</span>, don<span class="string">&#x27;t announce         │         rpdev-&gt;ept = NULL, don&#x27;</span>t announce</span><br><span class="line"> │                                                    │</span><br><span class="line"> │                                                    │</span><br><span class="line"> │ open(<span class="string">&quot;/dev/rpmsg_ctrl0&quot;</span>)                           │open(<span class="string">&quot;/dev/rpmsg_ctrl0&quot;</span>)</span><br><span class="line"> │ ioctl(fd, RPMSG_CREATE_EPT_IOCTL, &amp;eptinfo)        │ioctl(fd, RPMSG_CREATE_EPT_IOCTL, &amp;eptinfo)</span><br><span class="line"> │        eptinfo.name=<span class="string">&quot;tty&quot;</span>, src=<span class="number">0x300</span>, dst=<span class="number">0x400</span>    │        eptinfo.name=<span class="string">&quot;tty&quot;</span>, src=<span class="number">0x400</span>, dst=<span class="number">0x300</span></span><br><span class="line"> │    <span class="keyword">if</span> src = RPMSG_ADDR_ANY, ept-&gt;addr = idr_alloc()│    <span class="keyword">if</span> src = RPMSG_ADDR_ANY, ept-&gt;addr = idr_alloc()</span><br><span class="line"> │    rpmsg_eptdev_create(ctrldev, chinfo);           │    rpmsg_eptdev_create(ctrldev, chinfo);</span><br><span class="line"> │        create cdev <span class="string">&quot;rpmsg%d&quot;</span>                       │         create cdev <span class="string">&quot;rpmsg%d&quot;</span></span><br><span class="line"> │ open(<span class="string">&quot;/dev/rpmsg0&quot;</span>)                                │open(<span class="string">&quot;/dev/rpmsg0&quot;</span>)</span><br><span class="line"> │    rpmsg_create_ept(rpdev, rpmsg_ept_cb,           │  rpmsg_create_ept(rpdev, rpmsg_ept_cb,</span><br><span class="line"> │          eptdev, eptdev-&gt;chinfo);                  │        eptdev, eptdev-&gt;chinfo);</span><br><span class="line"> │      __rpmsg_create_ept                            │    __rpmsg_create_ept</span><br><span class="line"> │         ept-&gt;addr = <span class="number">0x300</span>                          │       ept-&gt;addr = <span class="number">0x400</span></span><br><span class="line"> │         ept-&gt;cb = rpmsg_ept_cb                     │       ept-&gt;cb = rpmsg_ept_cb</span><br><span class="line"> │                                                    │</span><br><span class="line"> │ write_iter(<span class="string">&quot;/dev/rpmsg0&quot;</span>)                          │read_iter(<span class="string">&quot;/dev/rpmsg0&quot;</span>)</span><br><span class="line"> │    rpmsg_eptdev_write_iter(iocb, from)             │  rpmsg_eptdev_read_iter(iocb, to)</span><br><span class="line"> │      rpmsg_send/trysend(eptdev-&gt;ept, kbuf, len);   │    wait_event_interruptible(eptdev-&gt;readq,</span><br><span class="line"> │        ept-&gt;ops-&gt;send                              │!skb_queue_empty(&amp;eptdev-&gt;<span class="built_in">queue</span>) ||</span><br><span class="line"> │           src=ept-&gt;addr, dst=rpdev-&gt;dst            │!eptdev-&gt;ept)</span><br><span class="line"> │           rpmsg_send_offchannel_raw()              │</span><br><span class="line"> │              get_a_tx_buf()                        │</span><br><span class="line"> │              fill rpmsg_hdr                        │</span><br><span class="line"> │              virtqueue_add_outbuf()                │</span><br><span class="line"> │              virtqueue_kick()                      │</span><br><span class="line"> │───────────────────────────────────────────────────►│</span><br><span class="line"> │                                                    │rpmsg_recv_done(rvq)</span><br><span class="line"> │                                                    │  rpmsg_recv_single(vrp, dev, msg, len)</span><br><span class="line"> │                                                    │    ept-&gt;cb() = rpmsg_ept_cb()</span><br><span class="line"> │                                                    │      skb_put_data(skb, buf, len);</span><br><span class="line"> │                                                    │      skb_queue_tail(&amp;eptdev-&gt;<span class="built_in">queue</span>, skb);</span><br><span class="line"> │                                                    │      wake_up_interruptible(&amp;eptdev-&gt;readq);</span><br><span class="line"> │                                                    │</span><br><span class="line"> │                                                    │</span><br><span class="line"> │                                                    │    wait_event_interruptible(eptdev-&gt;readq,</span><br><span class="line"> │                                                    │!skb_queue_empty(&amp;eptdev-&gt;<span class="built_in">queue</span>) ||</span><br><span class="line"> │                                                    │!eptdev-&gt;ept)</span><br><span class="line"> │                                                    │    skb = skb_dequeue(&amp;eptdev-&gt;<span class="built_in">queue</span>)</span><br><span class="line"> │                                                    │    copy_to_iter(skb-&gt;data, use, to)</span><br><span class="line"> │                                                    │    kfree_skb(skb)</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">This article introduces the bus abstraction mechanism of Rpmsg Core in Linux 5.10.23 and the access method of its backend, and discusses in detail the matching and scoring rules between devices and drivers as well as the device probing process. It summarizes core logic such as power domain association, automatic endpoint creation, and dynamic address allocation during probing, revealing the implementation details of the rpmsg framework in hardware power management and endpoint communication.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>Virtio Rpmsg Bus</title>
    <link href="https://even629.com/en/posts/202606230/"/>
    <id>https://even629.com/en/posts/202606230/</id>
    <published>2026-06-22T14:17:13.000Z</published>
    <updated>2026-06-22T14:17:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-06-22</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the implementation principles and core data structures of the virtio-based rpmsg bus driver in the Linux kernel. It discusses the basic communication model of rpmsg and provides a detailed analysis of the rpmsg_device、rpmsg_endpoint creation and destruction logic, as well as the underlying transport mechanisms such as virtqueue send/receive channels, buffer management, DMA mapping, and concurrency control within the virtproc_info private state.</blockquote><hr><blockquote><p>linux 5.10.238</p></blockquote><p><figure class="image-caption"><img loading="lazy" src="https://cdn.jsdelivr.net/gh/even629/myPicGo/shared/05.png" alt="rpmsg.drawio"><figcaption>rpmsg.drawio</figcaption></figure></p><h2 id="rpmsg-Structure">rpmsg Structure</h2><p>rpmsg has three layers:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">┌────────────────────────────────────────┐</span><br><span class="line">│ 业务层：rpmsg_driver                     │  ← 写业务的地方</span><br><span class="line">│ （rpmsg_tty / rpmsg_chrdev / 自定义）    │</span><br><span class="line">├────────────────────────────────────────┤</span><br><span class="line">│ rpmsg 总线 / core：rpmsg_core.c         │  ← 匹配 device 和 driver</span><br><span class="line">│ rpmsg_device / rpmsg_endpoint          │</span><br><span class="line">├────────────────────────────────────────┤</span><br><span class="line">│ transport 后端：virtio_rpmsg_bus.c      │  ← 本博客重点分析的代码</span><br><span class="line">│ （virtio_driver，搬运消息、造 channel）   │</span><br><span class="line">├────────────────────────────────────────┤</span><br><span class="line">│ virtio 总线 / vring                     │</span><br><span class="line">└────────────────────────────────────────┘</span><br></pre></td></tr></table></figure><p><code>virtio_rpmsg_bus.c</code>In the middle and lower layers, its responsibilities are:</p><ol><li>Take over the virtio rpmsg device</li><li>Use vring to send and receive messages</li><li>Create/destroy rpmsg_device based on name service</li></ol><p>It produces<code>rpmsg_device</code>, but does not consume. The consumer is<code>rpmsg_driver</code>。</p><h2 id="module-init-module-exit">module_init/module_exit</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">virtio_device_id</span> <span class="title">id_table</span>[] =</span> &#123;</span><br><span class="line">    &#123; VIRTIO_ID_RPMSG, VIRTIO_DEV_ANY_ID &#125;,</span><br><span class="line">    &#123; <span class="number">0</span> &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">unsigned</span> <span class="type">int</span> features[] = &#123;</span><br><span class="line">    VIRTIO_RPMSG_F_NS,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">virtio_driver</span> <span class="title">virtio_ipc_driver</span> =</span> &#123;</span><br><span class="line">    .feature_table= features,</span><br><span class="line">    .feature_table_size = ARRAY_SIZE(features),</span><br><span class="line">    .driver.name= KBUILD_MODNAME,</span><br><span class="line">    .driver.owner= THIS_MODULE,</span><br><span class="line">    .id_table= id_table,</span><br><span class="line">    .probe= rpmsg_probe,</span><br><span class="line">    .remove= rpmsg_remove,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">rpmsg_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    ret = register_virtio_driver(&amp;virtio_ipc_driver);</span><br><span class="line">    <span class="keyword">if</span> (ret)</span><br><span class="line">        pr_err(<span class="string">&quot;failed to register virtio driver: %d\n&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line">subsys_initcall(rpmsg_init);</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> __exit <span class="title function_">rpmsg_fini</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    unregister_virtio_driver(&amp;virtio_ipc_driver);</span><br><span class="line">&#125;</span><br><span class="line">module_exit(rpmsg_fini);</span><br><span class="line"></span><br><span class="line">MODULE_DEVICE_TABLE(virtio, id_table);</span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;Virtio-based remote processor messaging bus&quot;</span>);</span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL v2&quot;</span>);</span><br></pre></td></tr></table></figure><p><code>virtio_rpmsg_bus.c</code>is the Linux kernel’s<strong>virtio-based rpmsg bus driver</strong>. Its role is:</p><blockquote><p>Enable the Linux main core and remote processor to send and receive rpmsg messages via the virtio vring mechanism, and abstract the remote service into a Linux<code>rpmsg_device</code>, for upper-layer rpmsg driver binding and use.<br>This file itself is the<strong>virtio transport implementation of the rpmsg bus</strong>, it does not care about specific business protocols, such as audio, sensors, TEE, MCU control, etc.; it is only responsible for delivering messages to the corresponding endpoint.</p></blockquote><h2 id="Basic-Communication-Model">Basic Communication Model</h2><h3 id="rpmsg">rpmsg</h3><p>The communication unit of rpmsg is:</p><ul><li><code>rpmsg_device</code>rpmsg channel device, a communication channel, is a “device”</li><li><code>rpmsg_driver</code>The driver that handles the business of this channel</li><li><code>rpmsg_endpoint</code>The actual sending and receiving endpoints on the channel (address + callback)</li></ul><p>Relationship among the three:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">rpmsg_driver  ←—— 匹配 ——→  rpmsg_device</span><br><span class="line">                                 |</span><br><span class="line">                                 | 持有</span><br><span class="line">                                 v</span><br><span class="line">                            rpmsg_endpoint</span><br></pre></td></tr></table></figure><p>rpmsg_device is the middle “device managed by the driver”. When creating<code>rpmsg_device</code>, the probe function is triggered for matching, and upon successful matching, the<code>rpmsg_driver-&gt;probe</code>function is called</p><h4 id="struct-rpmsg-device">struct rpmsg_device</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span></span></span><br><span class="line"><span class="class">   ├── <span class="title">u32</span> <span class="title">src</span></span></span><br><span class="line"><span class="class">   ├── <span class="title">u32</span> <span class="title">dst</span></span></span><br><span class="line"><span class="class">   ├── <span class="title">bool</span> <span class="title">announce</span></span></span><br><span class="line"><span class="class">   ├── <span class="keyword">struct</span> <span class="title">device</span> <span class="title">dev</span></span></span><br><span class="line"><span class="class">   ├── <span class="keyword">struct</span> <span class="title">rpmsg_device_id</span> <span class="title">id</span>;</span></span><br><span class="line">   ├── <span class="type">const</span> <span class="type">char</span> *driver_override;</span><br><span class="line">   ├── <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_ops</span> *<span class="title">ops</span>;</span></span><br><span class="line">   └── <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept</span></span></span><br><span class="line"><span class="class">               ├── <span class="title">u32</span> <span class="title">addr</span></span></span><br><span class="line"><span class="class">               ├── <span class="title">void</span> *<span class="title">priv</span></span></span><br><span class="line"><span class="class">               ├── <span class="title">rpmsg_rx_cb_t</span> <span class="title">cb</span></span></span><br><span class="line"><span class="class">               ├── <span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">cb_lock</span></span></span><br><span class="line"><span class="class">               ├── <span class="keyword">struct</span> <span class="title">kref</span> <span class="title">refcount</span></span></span><br><span class="line"><span class="class">               ├── <span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span></span></span><br><span class="line"><span class="class">               └── <span class="title">const</span> <span class="keyword">struct</span> <span class="title">rpmsg_endpoint_ops</span> *<span class="title">ops</span> </span></span><br></pre></td></tr></table></figure><p>where<code>struct rpmsg_device</code>Defined as follows:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_device - device that belong to the rpmsg bus</span></span><br><span class="line"><span class="comment"> * @dev: the device struct</span></span><br><span class="line"><span class="comment"> * @id: device id (used to match between rpmsg drivers and devices)</span></span><br><span class="line"><span class="comment"> * @driver_override: driver name to force a match; do not set directly,</span></span><br><span class="line"><span class="comment"> *                   because core frees it; use driver_set_override() to</span></span><br><span class="line"><span class="comment"> *                   set or clear it.</span></span><br><span class="line"><span class="comment"> * @src: local address</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> * @ept: the rpmsg endpoint of this channel</span></span><br><span class="line"><span class="comment"> * @announce: if set, rpmsg will announce the creation/removal of this channel</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> <span class="title">dev</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_id</span> <span class="title">id</span>;</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> *driver_override;</span><br><span class="line">    u32 src;</span><br><span class="line">    u32 dst;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept</span>;</span></span><br><span class="line">    <span class="type">bool</span> announce;</span><br><span class="line"></span><br><span class="line">    <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_ops</span> *<span class="title">ops</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><blockquote><p><code>struct rpmsg_device_ops</code>represents a<code>rpmsg_device</code>operation</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* struct rpmsg_device_ops - indirection table for the rpmsg_device operations</span></span><br><span class="line"><span class="comment">* @create_ept:create backend-specific endpoint, required</span></span><br><span class="line"><span class="comment">* @announce_create:announce presence of new channel, optional</span></span><br><span class="line"><span class="comment">* @announce_destroy:announce destruction of channel, optional</span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">* Indirection table for the operations that a rpmsg backend should implement.</span></span><br><span class="line"><span class="comment">* @announce_create and @announce_destroy are optional as the backend might</span></span><br><span class="line"><span class="comment">* advertise new channels implicitly by creating the endpoints.</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device_ops</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *(*<span class="title">create_ept</span>)(<span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>,</span></span><br><span class="line"><span class="class">                        <span class="title">rpmsg_rx_cb_t</span> <span class="title">cb</span>, <span class="title">void</span> *<span class="title">priv</span>,</span></span><br><span class="line"><span class="class">                        <span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span>);</span></span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> (*announce_create)(<span class="keyword">struct</span> rpmsg_device *ept);</span><br><span class="line">    <span class="type">int</span> (*announce_destroy)(<span class="keyword">struct</span> rpmsg_device *ept);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>An rpmsg_device is equivalent to a logical channel, for example:</p><ul><li><code>channel name</code>: “rpmsg-demo”</li><li><code>src</code>: local endpoint address</li><li><code>dst</code>: remote endpoint address</li></ul><p>In<code>virtio_rpmsg_bus.c</code>, the channel is created like this (<code>rpmsg_create_channel()</code>）：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">rpdev-&gt;src = chinfo-&gt;src;</span><br><span class="line">rpdev-&gt;dst = chinfo-&gt;dst;</span><br><span class="line">rpdev-&gt;ops = &amp;virtio_rpmsg_ops;</span><br><span class="line"><span class="built_in">strncpy</span>(rpdev-&gt;id.name, chinfo-&gt;name, RPMSG_NAME_SIZE);</span><br></pre></td></tr></table></figure><p>That is: the remote announces a service “rpmsg-demo”, Linux creates a<code>rpmsg_device</code>representing this channel, or the local side actively creates a service “rpmsg-demo”, i.e., creates a<code>rpmsg_device</code>representing the local channel. After announcement, the NS service on the remote side also creates a channel for “rpmsg-demo”. The local and remote<code>rpmsg_device</code>have src and dst exactly opposite, and communicate through this channel.</p><p>In fact,<code>virtio_rpmsg_bus.c</code>the abstract rpmsg channel descriptor in is</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct virtio_rpmsg_channel - rpmsg channel descriptor</span></span><br><span class="line"><span class="comment"> * @rpdev: the rpmsg channel device</span></span><br><span class="line"><span class="comment"> * @vrp: the virtio remote processor device this channel belongs to</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This structure stores the channel that links the rpmsg device to the virtio</span></span><br><span class="line"><span class="comment"> * remote processor device.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">virtio_rpmsg_channel</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> <span class="title">rpdev</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>i.e., a<code>rpmsg_device</code>Also add the core data structure<code>struct virtproc_info *vrp</code>, which is the key data structure for virtio to implement the rpmsg bus</p><h4 id="struct-rpmsg-endpoint">struct rpmsg_endpoint</h4><p><code>rpmsg_device</code>Just like a telephone line + an extension number service, while<code>rpmsg_endpoint</code>represents the person actually answering the phone</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_endpoint - binds a local rpmsg address to its user</span></span><br><span class="line"><span class="comment"> * @rpdev: rpmsg channel device</span></span><br><span class="line"><span class="comment"> * @refcount: when this drops to zero, the ept is deallocated</span></span><br><span class="line"><span class="comment"> * @cb: rx callback handler</span></span><br><span class="line"><span class="comment"> * @cb_lock: must be taken before accessing/changing @cb</span></span><br><span class="line"><span class="comment"> * @addr: local rpmsg address</span></span><br><span class="line"><span class="comment"> * @priv: private data for the driver&#x27;s use</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as</span></span><br><span class="line"><span class="comment"> * it binds an rpmsg address with an rx callback handler.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Simple rpmsg drivers shouldn&#x27;t use this struct directly, because</span></span><br><span class="line"><span class="comment"> * things just work: every rpmsg driver provides an rx callback upon</span></span><br><span class="line"><span class="comment"> * registering to the bus, and that callback is then bound to its rpmsg</span></span><br><span class="line"><span class="comment"> * address when the driver is probed. When relevant inbound messages arrive</span></span><br><span class="line"><span class="comment"> * (i.e. messages which their dst address equals to the src address of</span></span><br><span class="line"><span class="comment"> * the rpmsg channel), the driver&#x27;s handler is invoked to process it.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * More complicated drivers though, that do need to allocate additional rpmsg</span></span><br><span class="line"><span class="comment"> * addresses, and bind them to different rx callbacks, must explicitly</span></span><br><span class="line"><span class="comment"> * create additional endpoints by themselves (see rpmsg_create_ept()).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kref</span> <span class="title">refcount</span>;</span></span><br><span class="line">    <span class="type">rpmsg_rx_cb_t</span> cb;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">cb_lock</span>;</span></span><br><span class="line">    u32 addr;</span><br><span class="line">    <span class="type">void</span> *priv;</span><br><span class="line"></span><br><span class="line">    <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint_ops</span> *<span class="title">ops</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>The logic related to rpmsg_endpoint is mainly in<code>rpmsg_core.c</code>, among which the most important are<code>rpmsg_rx_cb_t cb</code>and<code>const struct rpmsg_endpoint_ops *ops</code>these two members:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="title function_">int</span> <span class="params">(*<span class="type">rpmsg_rx_cb_t</span>)</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *, <span class="type">void</span> *, <span class="type">int</span>, <span class="type">void</span> *, u32)</span>;</span><br></pre></td></tr></table></figure><p>This function represents the callback triggered when the ept receives a message</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_endpoint_ops - indirection table for rpmsg_endpoint operations</span></span><br><span class="line"><span class="comment"> * @destroy_ept:see @rpmsg_destroy_ept(), required</span></span><br><span class="line"><span class="comment"> * @send:see @rpmsg_send(), required</span></span><br><span class="line"><span class="comment"> * @sendto:see @rpmsg_sendto(), optional</span></span><br><span class="line"><span class="comment"> * @send_offchannel:see @rpmsg_send_offchannel(), optional</span></span><br><span class="line"><span class="comment"> * @trysend:see @rpmsg_trysend(), required</span></span><br><span class="line"><span class="comment"> * @trysendto:see @rpmsg_trysendto(), optional</span></span><br><span class="line"><span class="comment"> * @trysend_offchannel:see @rpmsg_trysend_offchannel(), optional</span></span><br><span class="line"><span class="comment"> * @poll:see @rpmsg_poll(), optional</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Indirection table for the operations that a rpmsg backend should implement.</span></span><br><span class="line"><span class="comment"> * In addition to @destroy_ept, the backend must at least implement @send and</span></span><br><span class="line"><span class="comment"> * @trysend, while the variants sending data off-channel are optional.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint_ops</span> &#123;</span></span><br><span class="line">    <span class="type">void</span> (*destroy_ept)(<span class="keyword">struct</span> rpmsg_endpoint *ept);</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> (*send)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len);</span><br><span class="line">    <span class="type">int</span> (*sendto)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len, u32 dst);</span><br><span class="line">    <span class="type">int</span> (*send_offchannel)(<span class="keyword">struct</span> rpmsg_endpoint *ept, u32 src, u32 dst,</span><br><span class="line">                  <span class="type">void</span> *data, <span class="type">int</span> len);</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> (*trysend)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len);</span><br><span class="line">    <span class="type">int</span> (*trysendto)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="type">void</span> *data, <span class="type">int</span> len, u32 dst);</span><br><span class="line">    <span class="type">int</span> (*trysend_offchannel)(<span class="keyword">struct</span> rpmsg_endpoint *ept, u32 src, u32 dst,</span><br><span class="line">                 <span class="type">void</span> *data, <span class="type">int</span> len);</span><br><span class="line">    <span class="type">__poll_t</span> (*poll)(<span class="keyword">struct</span> rpmsg_endpoint *ept, <span class="keyword">struct</span> file *filp,</span><br><span class="line">                 poll_table *wait);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>represents the operation function of rpmsg_endpoint.</p><h5 id="Endpoint-creation">Endpoint creation</h5><p>The core function is:<code>__rpmsg_create_ept()</code>, which is the operation function of rpmsg_device</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* for more info, see below documentation of rpmsg_create_ept() */</span></span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *__<span class="title">rpmsg_create_ept</span>(<span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span>,</span></span><br><span class="line"><span class="class">                         <span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>,</span></span><br><span class="line"><span class="class">                         <span class="title">rpmsg_rx_cb_t</span> <span class="title">cb</span>,</span></span><br><span class="line"><span class="class">                         <span class="title">void</span> *<span class="title">priv</span>, <span class="title">u32</span> <span class="title">addr</span>)</span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="type">int</span> id_min, id_max, id;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span> =</span> rpdev ? &amp;rpdev-&gt;dev : &amp;vrp-&gt;vdev-&gt;dev;</span><br><span class="line"></span><br><span class="line">    ept = kzalloc(<span class="keyword">sizeof</span>(*ept), GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (!ept)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    kref_init(&amp;ept-&gt;refcount);</span><br><span class="line">    mutex_init(&amp;ept-&gt;cb_lock);</span><br><span class="line"></span><br><span class="line">    ept-&gt;rpdev = rpdev;</span><br><span class="line">    ept-&gt;cb = cb;</span><br><span class="line">    ept-&gt;priv = priv;</span><br><span class="line">    ept-&gt;ops = &amp;virtio_endpoint_ops;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* do we need to allocate a local address ? */</span></span><br><span class="line">    <span class="keyword">if</span> (addr == RPMSG_ADDR_ANY) &#123;</span><br><span class="line">        id_min = RPMSG_RESERVED_ADDRESSES;</span><br><span class="line">        id_max = <span class="number">0</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        id_min = addr;</span><br><span class="line">        id_max = addr + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    mutex_lock(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* bind the endpoint to an rpmsg address (and allocate one if needed) */</span></span><br><span class="line">    id = idr_alloc(&amp;vrp-&gt;endpoints, ept, id_min, id_max, GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (id &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        dev_err(dev, <span class="string">&quot;idr_alloc failed: %d\n&quot;</span>, id);</span><br><span class="line">        <span class="keyword">goto</span> free_ept;</span><br><span class="line">    &#125;</span><br><span class="line">    ept-&gt;addr = id;</span><br><span class="line"></span><br><span class="line">    mutex_unlock(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> ept;</span><br><span class="line"></span><br><span class="line">free_ept:</span><br><span class="line">    mutex_unlock(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line">    kref_put(&amp;ept-&gt;refcount, __ept_release);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> rpmsg_endpoint *<span class="title function_">virtio_rpmsg_create_ept</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev,</span></span><br><span class="line"><span class="params">                              <span class="type">rpmsg_rx_cb_t</span> cb,</span></span><br><span class="line"><span class="params">                              <span class="type">void</span> *priv,</span></span><br><span class="line"><span class="params">                              <span class="keyword">struct</span> rpmsg_channel_info chinfo)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtio_rpmsg_channel</span> *<span class="title">vch</span> =</span> to_virtio_rpmsg_channel(rpdev);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> __rpmsg_create_ept(vch-&gt;vrp, rpdev, cb, priv, chinfo.src);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol><li>Allocate<code>struct rpmsg_endpoint</code></li><li>Initialize reference count and callback lock</li><li>Record callback, private data, ops</li><li>Assign local address to endpoint</li><li>Insert<code>vrp-&gt;endpoints</code>this idr</li></ol><p>Key logic:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (addr == RPMSG_ADDR_ANY) &#123;</span><br><span class="line">    id_min = RPMSG_RESERVED_ADDRESSES;</span><br><span class="line">    id_max = <span class="number">0</span>;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    id_min = addr;</span><br><span class="line">    id_max = addr + <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>If the caller does not specify an address, dynamically allocate</li><li>Dynamic addresses start from<code>1024</code>start</li><li><code>0 ~ 1023</code>reserved for predefined services<br>While reserved address definition:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_RESERVED_ADDRESSES(1024)</span></span><br></pre></td></tr></table></figure><p>Endpoint address via<code>idr_alloc()</code>allocation:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">id = idr_alloc(&amp;vrp-&gt;endpoints, ept, id_min, id_max, GFP_KERNEL);</span><br></pre></td></tr></table></figure><h5 id="Endpoint-destruction">Endpoint destruction</h5><p>Core function:<code>__rpmsg_destroy_ept()</code>, it is the operation function of rpmsg_endpoint</p><ol><li>from<code>idr</code>delete endpoint from</li><li>set callback to<code>NULL</code></li><li>decrease reference count, release endpoint if necessary</li></ol><p>key code:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * __rpmsg_destroy_ept() - destroy an existing rpmsg endpoint</span></span><br><span class="line"><span class="comment"> * @vrp: virtproc which owns this ept</span></span><br><span class="line"><span class="comment"> * @ept: endpoing to destroy</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * An internal function which destroy an ept without assuming it is</span></span><br><span class="line"><span class="comment"> * bound to an rpmsg channel. This is needed for handling the internal</span></span><br><span class="line"><span class="comment"> * name service endpoint, which isn&#x27;t bound to an rpmsg channel.</span></span><br><span class="line"><span class="comment"> * See also __rpmsg_create_ept().</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span></span><br><span class="line">__rpmsg_destroy_ept(<span class="keyword">struct</span> virtproc_info *vrp, <span class="keyword">struct</span> rpmsg_endpoint *ept)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* make sure new inbound messages can&#x27;t find this ept anymore */</span></span><br><span class="line">    mutex_lock(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line">    idr_remove(&amp;vrp-&gt;endpoints, ept-&gt;addr);</span><br><span class="line">    mutex_unlock(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* make sure in-flight inbound messages won&#x27;t invoke cb anymore */</span></span><br><span class="line">    mutex_lock(&amp;ept-&gt;cb_lock);</span><br><span class="line">    ept-&gt;cb = <span class="literal">NULL</span>;</span><br><span class="line">    mutex_unlock(&amp;ept-&gt;cb_lock);</span><br><span class="line"></span><br><span class="line">    kref_put(&amp;ept-&gt;refcount, __ept_release);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>pay special attention to concurrency here:</p><ul><li>delete idr: prevent new RX messages from finding this endpoint</li><li>set<code>cb = NULL</code>: prevent in-flight RX that already obtained the endpoint from calling callback</li><li><code>kref</code>: prevent release while RX path is using the endpoint</li></ul><h3 id="struct-virtproc-info">struct virtproc_info</h3><p>core data structure:<code>struct virtproc_info</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtio_device</span> *<span class="title">vdev</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtqueue</span> *<span class="title">rvq</span>, *<span class="title">svq</span>;</span></span><br><span class="line">    <span class="type">void</span> *rbufs, *sbufs;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> num_bufs;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> buf_size;</span><br><span class="line">    <span class="type">int</span> last_sbuf;</span><br><span class="line">    <span class="type">dma_addr_t</span> bufs_dma;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">tx_lock</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">idr</span> <span class="title">endpoints</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> <span class="title">endpoints_lock</span>;</span></span><br><span class="line">    <span class="type">wait_queue_head_t</span> sendq;</span><br><span class="line">    <span class="type">atomic_t</span> sleepers;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ns_ept</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>this is the private state of the entire virtio rpmsg device, attached to<code>vdev-&gt;priv = vrp</code>, divided by function</p><ul><li>virtio basics:<ul><li><code>vdev</code>underlying virtio device</li></ul></li><li>TX/RX channels:<ul><li><code>rvq</code>, <code>svq</code>           RX/TX virtqueue</li></ul></li><li>Buffer management:<ul><li><code>rbufs</code>, <code>sbufs</code>RX/TX buffer virtual address</li><li><code>num_bufs</code>Total buffer count</li><li><code>buf_size</code>Single buffer size</li><li><code>last_sbuf</code>TX pioneer cursor</li><li><code>bufs_dma</code>Buffer DMA base address</li></ul></li><li>Transmission synchronization:<ul><li><code>tx_lock</code>Protect svq/sbufs/sleepers</li><li><code>sendq</code>Wait queue for TX buffers</li><li><code>sleepers</code>Waiter count (controls tx-complete interrupt)</li></ul></li><li>Endpoint management:<ul><li><code>endpoints</code>Endpoint idr (lookup by address)</li><li><code>endpoints_lock</code>Protect endpoint table</li></ul></li><li>name service：<ul><li><code>ns_ept</code>Name service endpoint (addr 53)</li></ul></li></ul><h4 id="struct-virtio-device-vdev"><code>struct virtio_device *vdev</code></h4><p>Purpose: points to the underlying virtio device. It is the root of this rpmsg instance. Through it, you can obtain:<br>- vdev-&gt;dev       device node (dev_err/dev_for debugging)<br>- vdev-&gt;config    virtio configuration operations (reset/del_vqs, etc.)<br>- vdev-&gt;priv      points back to vrp itself<br>Set in probe:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;vdev = vdev;</span><br><span class="line">...</span><br><span class="line">vdev-&gt;priv = vrp;</span><br></pre></td></tr></table></figure><p>In callback, it relies on this to retrieve vrp:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span> =</span> rvq-&gt;vdev-&gt;priv;</span><br></pre></td></tr></table></figure><h4 id="struct-virtqueue-rvq-svq"><code>struct virtqueue *rvq, *svq</code></h4><p>Purpose:</p><ul><li>rvq = receive virtqueue: remote -&gt; Linux</li><li>svq = send virtqueue:   Linux -&gt; remote<br>These are the two channels for receiving and sending. In probe:</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;rvq = vqs[<span class="number">0</span>];   <span class="comment">/* input  */</span></span><br><span class="line">vrp-&gt;svq = vqs[<span class="number">1</span>];   <span class="comment">/* output */</span></span><br></pre></td></tr></table></figure><ul><li>Receiving messages:<code>virtqueue_get_buf(rvq)</code> / <code>virtqueue_add_inbuf(rvq)</code></li><li>Sending messages:<code>virtqueue_add_outbuf(svq)</code> / <code>virtqueue_get_buf(svq)</code></li></ul><h4 id="void-rbufs-sbufs"><code>void *rbufs, *sbufs</code></h4><p>Purpose:</p><ul><li>rbufs: starting kernel virtual address of the RX buffer area</li><li>sbufs: starting kernel virtual address of the TX buffer region</li></ul><p>In probe, split a whole DMA memory block into two halves:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;rbufs = bufs_va;                     <span class="comment">/* first half: RX */</span></span><br><span class="line">vrp-&gt;sbufs = bufs_va + total_buf_space / <span class="number">2</span>; <span class="comment">/* second half: TX */</span></span><br></pre></td></tr></table></figure><p>as shown in the figure</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bufs_va</span><br><span class="line">  ├── rbufs：RX[0] RX[1] ...</span><br><span class="line">  └── sbufs：TX[0] TX[1] ...</span><br></pre></td></tr></table></figure><p><code>get_a_tx_buf()</code>That is, get the TX buffer from sbufs by index:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ret = vrp-&gt;sbufs + vrp-&gt;buf_size * vrp-&gt;last_sbuf++;</span><br></pre></td></tr></table></figure><h4 id="unsigned-int-num-bufs"><code>unsigned int num_bufs</code></h4><p>Purpose: total number of RX + TX buffers (each half). Calculated in probe based on vring size:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (virtqueue_get_vring_size(vrp-&gt;rvq) &lt; MAX_RPMSG_NUM_BUFS / <span class="number">2</span>)</span><br><span class="line">      vrp-&gt;num_bufs = virtqueue_get_vring_size(vrp-&gt;rvq) * <span class="number">2</span>;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">      vrp-&gt;num_bufs = MAX_RPMSG_NUM_BUFS;  <span class="comment">/* 512 */</span></span><br></pre></td></tr></table></figure><p>Therefore:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">RX buffer 数 = num_bufs / 2</span><br><span class="line">TX buffer 数 = num_bufs / 2</span><br></pre></td></tr></table></figure><p>Used in many places as<code>num_bufs / 2</code>as a boundary, for example<code>get_a_tx_buf()</code>：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (vrp-&gt;last_sbuf &lt; vrp-&gt;num_bufs / <span class="number">2</span>)</span><br></pre></td></tr></table></figure><h4 id="unsigned-int-buf-size"><code>unsigned int buf_size</code></h4><p>Purpose: byte size of a single buffer, currently fixed at 512 (MAX_RPMSG_BUF_SIZE）。</p><p>In the probe function</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;buf_size = MAX_RPMSG_BUF_SIZE;</span><br></pre></td></tr></table></figure><p>It determines:</p><ul><li>address stride of each buffer:<code>sbufs + buf_size * i</code></li><li>upper limit of a single message payload</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (len &gt; vrp-&gt;buf_size - <span class="keyword">sizeof</span>(<span class="keyword">struct</span> rpmsg_hdr))</span><br><span class="line">      <span class="keyword">return</span> -EMSGSIZE;</span><br></pre></td></tr></table></figure><h4 id="int-last-sbuf"><code>int last_sbuf</code></h4><p>Function: The “pioneer cursor” of TX buffer, recording how many have been initially allocated in order. In<code>get_a_tx_buf()</code>used in:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (vrp-&gt;last_sbuf &lt; vrp-&gt;num_bufs / <span class="number">2</span>)</span><br><span class="line">      ret = vrp-&gt;sbufs + vrp-&gt;buf_size * vrp-&gt;last_sbuf++;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">      ret = virtqueue_get_buf(vrp-&gt;svq, &amp;len);</span><br></pre></td></tr></table></figure><ul><li><code>last_sbuf &lt; num_bufs/2</code>: If there are unused new TX buffers, take them in order</li><li>Otherwise: All TX buffers have been used, switch to recycling from the used ring<br>Once the upper limit is reached,<code>last_sbuf</code>it stops growing and relies entirely on<code>virtqueue_get_buf()</code>recycling.</li></ul><h4 id="dma-addr-t-bufs-dma"><code>dma_addr_t bufs_dma</code></h4><p>Function: The DMA base address of the entire buffer (address from device/DMA perspective). In probe, it is<code>dma_alloc_coherent()</code>returned by:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">bufs_va = dma_alloc_coherent(vdev-&gt;dev.parent,</span><br><span class="line">                           total_buf_space, &amp;vrp-&gt;bufs_dma, GFP_KERNEL);</span><br></pre></td></tr></table></figure><p><code>rbufs/sbufs</code>is the virtual address used by CPU, bufs_dma is the physical/bus address used for release and DMA mapping. Use it to release during remove:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">dma_free_coherent(vdev-&gt;dev.parent, total_buf_space,</span><br><span class="line">                vrp-&gt;rbufs, vrp-&gt;bufs_dma);</span><br></pre></td></tr></table></figure><h4 id="struct-mutex-tx-lock"><code>struct mutex tx_lock</code></h4><p>Function: Protects shared state on the sending side: svq, sbufs, sleepers. Allows multiple senders to call concurrently<code>rpmsg_send()</code>. A mutex is used because sending may need to wake up a remote processor that is “napping”, and this process may sleep, so a sleepable mutex must be used.</p><h4 id="struct-idr-endpoints"><code>struct idr endpoints</code></h4><p>Function: The idr index table for all local endpoints, with the key being the endpoint address. Used to quickly find an endpoint by address. This is the core data structure for message distribution. When creating an endpoint, allocate an address and insert:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">id = idr_alloc(&amp;vrp-&gt;endpoints, ept, id_min, id_max, GFP_KERNEL);</span><br><span class="line">ept-&gt;addr = id;</span><br></pre></td></tr></table></figure><p>When receiving a message, look up by dst:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ept = idr_find(&amp;vrp-&gt;endpoints, virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;dst));</span><br></pre></td></tr></table></figure><p>So rpmsg is actually<code>address-based dispatch</code>, it relies on this idr.</p><h4 id="struct-mutex-endpoints-lock"><code>struct mutex endpoints_lock</code></h4><p>Purpose: Protect concurrent access to the endpoints idr. Must hold when adding, deleting, querying, or modifying endpoints:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">mutex_lock(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line">ept = idr_find(&amp;vrp-&gt;endpoints, ...);</span><br><span class="line"><span class="keyword">if</span> (ept)</span><br><span class="line">      kref_get(&amp;ept-&gt;refcount);   <span class="comment">/* After finding, first add a reference to prevent release */</span></span><br><span class="line">mutex_unlock(&amp;vrp-&gt;endpoints_lock);</span><br></pre></td></tr></table></figure><p>Note that it and tx_lock are two different locks:<br>- <code>tx_lock</code>Protects the send path<br>- <code>endpoints_lock</code>Protects the endpoint table</p><h4 id="wait-queue-head-t-sendq"><code> wait_queue_head_t sendq</code></h4><p>Purpose: Senders waiting for a TX buffer sleep on this wait queue. When there is no TX buffer, rpmsg_send() sleeps and waits:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">wait_event_interruptible_timeout(vrp-&gt;sendq,</span><br><span class="line">                      (msg = get_a_tx_buf(vrp)),</span><br><span class="line">                      msecs_to_jiffies(<span class="number">15000</span>));</span><br></pre></td></tr></table></figure><p>After the remote side consumes the TX buffer, the TX complete callback wakes it up:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">rpmsg_xmit_done</span><span class="params">(<span class="keyword">struct</span> virtqueue *svq)</span></span><br><span class="line">&#123;</span><br><span class="line">      <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span> =</span> svq-&gt;vdev-&gt;priv;</span><br><span class="line">      wake_up_interruptible(&amp;vrp-&gt;sendq);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="atomic-t-sleepers"><code>atomic_t sleepers</code></h4><p>Purpose: How many senders are currently waiting for a TX buffer (waiter count). It works with the dynamic toggling of the TX complete interrupt:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* First waiter: Enable tx-complete callback */</span></span><br><span class="line"><span class="keyword">if</span> (atomic_inc_return(&amp;vrp-&gt;sleepers) == <span class="number">1</span>)</span><br><span class="line">      virtqueue_enable_cb(vrp-&gt;svq);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Last waiter: Disable tx-complete callback */</span></span><br><span class="line"><span class="keyword">if</span> (atomic_dec_and_test(&amp;vrp-&gt;sleepers))</span><br><span class="line">      virtqueue_disable_cb(vrp-&gt;svq);</span><br></pre></td></tr></table></figure><p>Design purpose:</p><ul><li>No one waiting for TX buffer: Disable tx-complete interrupt to save overhead</li><li>Someone waiting for TX buffer: Enable tx-complete interrupt, wake up immediately after remote returns buffer</li></ul><p>(This is the design of version 5.10. The Linux 7.1.1 version has removed sleepers due to the introduction of poll support.)</p><h4 id="struct-rpmsg-endpoint-ns-ept"><code>struct rpmsg_endpoint *ns_ept</code></h4><p>Purpose: dedicated endpoint for name service (fixed address 53). It does not belong to any ordinary rpmsg channel; it is used internally by the bus to handle remote service ‘create/destroy’ notifications. It is created in probe when the remote side supports the NS feature:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)) &#123;</span><br><span class="line">      vrp-&gt;ns_ept = __rpmsg_create_ept(vrp, <span class="literal">NULL</span>, rpmsg_ns_cb,</span><br><span class="line">                                       vrp, RPMSG_NS_ADDR);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Its callback is<code>rpmsg_ns_cb()</code>, responsible for creating/destroying rpmsg_device according to NS messages. It is destroyed separately during remove:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (vrp-&gt;ns_ept)</span><br><span class="line">      __rpmsg_destroy_ept(vrp, vrp-&gt;ns_ept);</span><br></pre></td></tr></table></figure><p>Note that rpdev is passed as NULL during creation because it is not bound to a specific channel.</p><h3 id="Buffer-Design">Buffer Design</h3><p>The driver uses fixed-size buffers. Related definitions:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> MAX_RPMSG_NUM_BUFS(512)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MAX_RPMSG_BUF_SIZE(512)</span></span><br></pre></td></tr></table></figure><ul><li>Up to 512 buffers</li><li>Half RX, half TX</li><li>Each buffer is 512 bytes</li><li>Maximum total memory: 512 * 512 = 256 KiB</li></ul><p>That is:</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">总 buffer 区域</span><br><span class="line">+------------------------+  &lt;-- vrp-&gt;rbufs = bufs<span class="built_in">_</span>va = dma<span class="built_in">_</span>alloc<span class="built_in">_</span>coherent(vdev-&gt;dev.parent,</span><br><span class="line">|                        |                    total<span class="built_in">_</span>buf<span class="built_in">_</span>space, <span class="built_in">&amp;</span>vrp-&gt;bufs<span class="built_in">_</span>dma,GFP<span class="built_in">_</span>KERNEL);</span><br><span class="line">|   RX Buffer (前一半)   |</span><br><span class="line">|                        |</span><br><span class="line">+------------------------+  &lt;-- vrp-&gt;sbufs = bufs<span class="built_in">_</span>va + total<span class="built_in">_</span>buf<span class="built_in">_</span>space / 2;</span><br><span class="line">|                        |</span><br><span class="line">|   TX Buffer (后一半)   |</span><br><span class="line">|                        |</span><br><span class="line">+------------------------+  &lt;-- vrp-&gt;rbufs + total<span class="built_in">_</span>buf<span class="built_in">_</span>space</span><br></pre></td></tr></table></figure><p>Allocated in probe:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bufs_va = dma_alloc_coherent(vdev-&gt;dev.parent,</span><br><span class="line">                     total_buf_space, &amp;vrp-&gt;bufs_dma,</span><br><span class="line">                     GFP_KERNEL);</span><br></pre></td></tr></table></figure><p>Then split:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;rbufs = bufs_va;</span><br><span class="line">vrp-&gt;sbufs = bufs_va + total_buf_space / <span class="number">2</span>;</span><br></pre></td></tr></table></figure><p>Each sent message has a common header:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_hdr</span> &#123;</span></span><br><span class="line">    __virtio32 src;</span><br><span class="line">    __virtio32 dst;</span><br><span class="line">    __virtio32 reserved;</span><br><span class="line">    __virtio16 len;</span><br><span class="line">    __virtio16 flags;</span><br><span class="line">    u8 data[];</span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><p>Meaning:</p><div class="table-wrap"><table><thead><tr><th>Field</th><th>Meaning</th></tr></thead><tbody><tr><td><code>src</code></td><td>Source endpoint address</td></tr><tr><td><code>dst</code></td><td>Destination endpoint address</td></tr><tr><td><code>reserved</code></td><td>Reserved</td></tr><tr><td><code>len</code></td><td>Payload length</td></tr><tr><td><code>flags</code></td><td>Message flags</td></tr><tr><td><code>data[]</code></td><td>Actual business data</td></tr></tbody></table></div><p>After Linux receives the message, it will<code>dst</code>find the local endpoint by the address, and then call the callback of that endpoint.</p><h4 id="get-a-tx-buf"><code>get_a_tx_buf()</code></h4><p>Code:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* super simple buffer &quot;allocator&quot; that is just enough for now */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> *<span class="title function_">get_a_tx_buf</span><span class="params">(<span class="keyword">struct</span> virtproc_info *vrp)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> len;</span><br><span class="line">    <span class="type">void</span> *ret;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* support multiple concurrent senders */</span></span><br><span class="line">    mutex_lock(&amp;vrp-&gt;tx_lock);</span><br><span class="line"></span><br><span class="line"><span class="number">4</span><span class="comment">/*</span></span><br><span class="line"><span class="comment">     * either pick the next unused tx buffer</span></span><br><span class="line"><span class="comment">     * (half of our buffers are used for sending messages)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (vrp-&gt;last_sbuf &lt; vrp-&gt;num_bufs / <span class="number">2</span>)</span><br><span class="line">        ret = vrp-&gt;sbufs + vrp-&gt;buf_size * vrp-&gt;last_sbuf++;</span><br><span class="line">    <span class="comment">/* or recycle a used one */</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        ret = virtqueue_get_buf(vrp-&gt;svq, &amp;len);</span><br><span class="line"></span><br><span class="line">    mutex_unlock(&amp;vrp-&gt;tx_lock);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This function is a very simple TX buffer allocator.</p><p>It has two phases:</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">阶段 1：还有从未使用过的 TX buffer</span><br><span class="line">    按数组顺序从 vrp-&gt;sbufs 里拿</span><br><span class="line"></span><br><span class="line">阶段 2：所有 TX buffer 都至少用过一次</span><br><span class="line">    从 svq used ring 回收远端已经读完的 TX buffer</span><br></pre></td></tr></table></figure><p><code>last_sbuf</code>Only useful in the first phase.</p><p>Once:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;last_sbuf == vrp-&gt;num_bufs / <span class="number">2</span></span><br></pre></td></tr></table></figure><p>Then just keep going:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">virtqueue_get_buf(vrp-&gt;svq, &amp;len);</span><br></pre></td></tr></table></figure><p>That is to say:</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">last<span class="built_in">_</span>sbuf = 一次性“开荒游标”</span><br><span class="line">virtqueue<span class="built_in">_</span>get<span class="built_in">_</span>buf() = 后续复用 buffer 的来源</span><br></pre></td></tr></table></figure><h2 id="virtio-API">virtio API</h2><div class="table-wrap"><table><thead><tr><th>API</th><th>Function</th></tr></thead><tbody><tr><td><code>virtio_find_vqs()</code></td><td>Find/Create virtqueue</td></tr><tr><td><code>virtqueue_add_inbuf()</code></td><td>Give the device a “writable” buffer</td></tr><tr><td><code>virtqueue_add_outbuf()</code></td><td>Give the device a “readable” buffer</td></tr><tr><td><code>virtqueue_add_sgs</code></td><td>Generic buffer addition function includes in and out</td></tr><tr><td><code>virtqueue_get_buf()</code></td><td>Retrieve the buffer processed by the device from the used ring</td></tr><tr><td><code>virtqueue_kick()</code></td><td>Notify the other side: the queue has a new buffer</td></tr><tr><td><code>virtqueue_kick_prepare()</code></td><td>Determine whether notification is needed</td></tr><tr><td><code>virtqueue_notify()</code></td><td>Actually send the notification</td></tr><tr><td><code>virtqueue_enable_cb()</code></td><td>Enable virtqueue callback/interrupt</td></tr><tr><td><code>virtqueue_disable_cb()</code></td><td>Disable virtqueue callback/interrupt, used to prevent interrupt storms during polling</td></tr><tr><td><code>virtqueue_get_vring_size()</code></td><td>Get ring size</td></tr><tr><td><code>virtio_has_feature()</code></td><td>Check virtio feature</td></tr><tr><td><code>virtio_device_ready()</code></td><td>Set DRIVER_OK, the device can start working</td></tr></tbody></table></div><h2 id="probe-function">probe function</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">virtio_driver</span> <span class="title">virtio_ipc_driver</span> =</span> &#123;</span><br><span class="line">    .feature_table= features,</span><br><span class="line">    .feature_table_size = ARRAY_SIZE(features),</span><br><span class="line">    .driver.name= KBUILD_MODNAME,</span><br><span class="line">    .driver.owner= THIS_MODULE,</span><br><span class="line">    .id_table= id_table,</span><br><span class="line">    .probe= rpmsg_probe,</span><br><span class="line">    .remove= rpmsg_remove,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><code>virtio_driver.probe</code>The function is defined as:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_probe</span><span class="params">(<span class="keyword">struct</span> virtio_device *vdev)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">vq_callback_t</span> *vq_cbs[] = &#123; rpmsg_recv_done, rpmsg_xmit_done &#125;;</span><br><span class="line">    <span class="type">static</span> <span class="type">const</span> <span class="type">char</span> * <span class="type">const</span> names[] = &#123; <span class="string">&quot;input&quot;</span>, <span class="string">&quot;output&quot;</span> &#125;;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtqueue</span> *<span class="title">vqs</span>[2];</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span>;</span></span><br><span class="line">    <span class="type">void</span> *bufs_va;</span><br><span class="line">    <span class="type">int</span> err = <span class="number">0</span>, i;</span><br><span class="line">    <span class="type">size_t</span> total_buf_space;</span><br><span class="line">    <span class="type">bool</span> notify;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Allocate struct virtproc_info</span></span><br><span class="line">    vrp = kzalloc(<span class="keyword">sizeof</span>(*vrp), GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (!vrp)</span><br><span class="line">        <span class="keyword">return</span> -ENOMEM;</span><br><span class="line"></span><br><span class="line">    vrp-&gt;vdev = vdev;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Initialize members of struct virtproc_info</span></span><br><span class="line">    idr_init(&amp;vrp-&gt;endpoints);</span><br><span class="line">    mutex_init(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line">    mutex_init(&amp;vrp-&gt;tx_lock);</span><br><span class="line">    init_waitqueue_head(&amp;vrp-&gt;sendq);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* We expect two virtqueues, rx and tx (and in this order) */</span></span><br><span class="line">    err = virtio_find_vqs(vdev, <span class="number">2</span>, vqs, vq_cbs, names, <span class="literal">NULL</span>);</span><br><span class="line">    <span class="keyword">if</span> (err)</span><br><span class="line">        <span class="keyword">goto</span> free_vrp;</span><br><span class="line"></span><br><span class="line">    vrp-&gt;rvq = vqs[<span class="number">0</span>];</span><br><span class="line">    vrp-&gt;svq = vqs[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* we expect symmetric tx/rx vrings */</span></span><br><span class="line">    WARN_ON(virtqueue_get_vring_size(vrp-&gt;rvq) !=</span><br><span class="line">        virtqueue_get_vring_size(vrp-&gt;svq));</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* we need less buffers if vrings are small */</span></span><br><span class="line">    <span class="keyword">if</span> (virtqueue_get_vring_size(vrp-&gt;rvq) &lt; MAX_RPMSG_NUM_BUFS / <span class="number">2</span>)</span><br><span class="line">        vrp-&gt;num_bufs = virtqueue_get_vring_size(vrp-&gt;rvq) * <span class="number">2</span>;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        vrp-&gt;num_bufs = MAX_RPMSG_NUM_BUFS;</span><br><span class="line"></span><br><span class="line">    vrp-&gt;buf_size = MAX_RPMSG_BUF_SIZE;</span><br><span class="line"></span><br><span class="line">    total_buf_space = vrp-&gt;num_bufs * vrp-&gt;buf_size;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* allocate coherent memory for the buffers */</span></span><br><span class="line">    bufs_va = dma_alloc_coherent(vdev-&gt;dev.parent,</span><br><span class="line">                     total_buf_space, &amp;vrp-&gt;bufs_dma,</span><br><span class="line">                     GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (!bufs_va) &#123;</span><br><span class="line">        err = -ENOMEM;</span><br><span class="line">        <span class="keyword">goto</span> vqs_del;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    dev_dbg(&amp;vdev-&gt;dev, <span class="string">&quot;buffers: va %pK, dma %pad\n&quot;</span>,</span><br><span class="line">        bufs_va, &amp;vrp-&gt;bufs_dma);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* half of the buffers is dedicated for RX */</span></span><br><span class="line">    vrp-&gt;rbufs = bufs_va;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* and half is dedicated for TX */</span></span><br><span class="line">    vrp-&gt;sbufs = bufs_va + total_buf_space / <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* set up the receive buffers */</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; vrp-&gt;num_bufs / <span class="number">2</span>; i++) &#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">scatterlist</span> <span class="title">sg</span>;</span></span><br><span class="line">        <span class="type">void</span> *cpu_addr = vrp-&gt;rbufs + i * vrp-&gt;buf_size;</span><br><span class="line"></span><br><span class="line">        rpmsg_sg_init(&amp;sg, cpu_addr, vrp-&gt;buf_size);</span><br><span class="line"></span><br><span class="line">        err = virtqueue_add_inbuf(vrp-&gt;rvq, &amp;sg, <span class="number">1</span>, cpu_addr,</span><br><span class="line">                      GFP_KERNEL);</span><br><span class="line">        WARN_ON(err); <span class="comment">/* sanity check; this can&#x27;t really happen */</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* suppress &quot;tx-complete&quot; interrupts */</span></span><br><span class="line">    virtqueue_disable_cb(vrp-&gt;svq);</span><br><span class="line"></span><br><span class="line">    vdev-&gt;priv = vrp;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* if supported by the remote processor, enable the name service */</span></span><br><span class="line">    <span class="keyword">if</span> (virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)) &#123;</span><br><span class="line">        <span class="comment">/* a dedicated endpoint handles the name service msgs */</span></span><br><span class="line">        vrp-&gt;ns_ept = __rpmsg_create_ept(vrp, <span class="literal">NULL</span>, rpmsg_ns_cb,</span><br><span class="line">                        vrp, RPMSG_NS_ADDR);</span><br><span class="line">        <span class="keyword">if</span> (!vrp-&gt;ns_ept) &#123;</span><br><span class="line">            dev_err(&amp;vdev-&gt;dev, <span class="string">&quot;failed to create the ns ept\n&quot;</span>);</span><br><span class="line">            err = -ENOMEM;</span><br><span class="line">            <span class="keyword">goto</span> free_coherent;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * Prepare to kick but don&#x27;t notify yet - we can&#x27;t do this before</span></span><br><span class="line"><span class="comment">     * device is ready.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    notify = virtqueue_kick_prepare(vrp-&gt;rvq);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* From this point on, we can notify and get callbacks. */</span></span><br><span class="line">    virtio_device_ready(vdev);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* tell the remote processor it can start sending messages */</span></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * this might be concurrent with callbacks, but we are only</span></span><br><span class="line"><span class="comment">     * doing notify, not a full kick here, so that&#x27;s ok.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (notify)</span><br><span class="line">        virtqueue_notify(vrp-&gt;rvq);</span><br><span class="line"></span><br><span class="line">    dev_info(&amp;vdev-&gt;dev, <span class="string">&quot;rpmsg host is online\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">free_coherent:</span><br><span class="line">    dma_free_coherent(vdev-&gt;dev.parent, total_buf_space,</span><br><span class="line">              bufs_va, vrp-&gt;bufs_dma);</span><br><span class="line">vqs_del:</span><br><span class="line">    vdev-&gt;config-&gt;del_vqs(vrp-&gt;vdev);</span><br><span class="line">free_vrp:</span><br><span class="line">    kfree(vrp);</span><br><span class="line">    <span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Analysis as follows</p><h3 id="Allocatevirtproc-info">Allocate<code>virtproc_info</code></h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vrp = kzalloc(<span class="keyword">sizeof</span>(*vrp), GFP_KERNEL);</span><br></pre></td></tr></table></figure><p>Initialize:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">idr_init(&amp;vrp-&gt;endpoints);</span><br><span class="line">mutex_init(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line">mutex_init(&amp;vrp-&gt;tx_lock);</span><br><span class="line">init_waitqueue_head(&amp;vrp-&gt;sendq);</span><br></pre></td></tr></table></figure><h3 id="Find-virtqueue">Find virtqueue</h3><p>The driver needs two virtqueues:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">vq_callback_t</span> *vq_cbs[] = &#123; rpmsg_recv_done, rpmsg_xmit_done &#125;;</span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="type">char</span> * <span class="type">const</span> names[] = &#123; <span class="string">&quot;input&quot;</span>, <span class="string">&quot;output&quot;</span> &#125;;</span><br></pre></td></tr></table></figure><p>Then:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">err = virtio_find_vqs(vdev, <span class="number">2</span>, vqs, vq_cbs, names, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure><p>Two queues:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;rvq = vqs[<span class="number">0</span>];</span><br><span class="line">vrp-&gt;svq = vqs[<span class="number">1</span>];</span><br></pre></td></tr></table></figure><p>Meaning:</p><div class="table-wrap"><table><thead><tr><th>virtqueue</th><th>Purpose</th><th>callback</th></tr></thead><tbody><tr><td><code>rvq</code> / input</td><td>Linux receives messages from the remote end</td><td><code>rpmsg_recv_done()</code></td></tr><tr><td><code>svq</code> / output</td><td>Linux sends a message to the remote end</td><td><code>rpmsg_xmit_done()</code></td></tr></tbody></table></div><h3 id="Calculate-the-number-of-buffers">Calculate the number of buffers</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (virtqueue_get_vring_size(vrp-&gt;rvq) &lt; MAX_RPMSG_NUM_BUFS / <span class="number">2</span>)</span><br><span class="line">    vrp-&gt;num_bufs = virtqueue_get_vring_size(vrp-&gt;rvq) * <span class="number">2</span>;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    vrp-&gt;num_bufs = MAX_RPMSG_NUM_BUFS;</span><br></pre></td></tr></table></figure><p>That is: if the vring is small, reduce the number of buffers according to the vring capacity; otherwise, at most 512 buffers</p><h3 id="Allocate-coherent-DMA-buffer">Allocate coherent DMA buffer</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">bufs_va = dma_alloc_coherent(vdev-&gt;dev.parent,</span><br><span class="line">                 total_buf_space, &amp;vrp-&gt;bufs_dma,</span><br><span class="line">                 GFP_KERNEL);</span><br></pre></td></tr></table></figure><p>This buffer is shared DMA memory accessible by both the main core and the virtio backend.</p><h3 id="Pre-place-RX-buffers-into-the-RX-virtqueue">Pre-place RX buffers into the RX virtqueue</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; vrp-&gt;num_bufs / <span class="number">2</span>; i++) &#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">scatterlist</span> <span class="title">sg</span>;</span></span><br><span class="line">    <span class="type">void</span> *cpu_addr = vrp-&gt;rbufs + i * vrp-&gt;buf_size;</span><br><span class="line"></span><br><span class="line">    rpmsg_sg_init(&amp;sg, cpu_addr, vrp-&gt;buf_size);</span><br><span class="line"></span><br><span class="line">    err = virtqueue_add_inbuf(vrp-&gt;rvq, &amp;sg, <span class="number">1</span>, cpu_addr,</span><br><span class="line">                  GFP_KERNEL);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This step is crucial:</p><blockquote><p>Linux first places a batch of empty RX buffers into the available ring, so that the remote processor can later write messages into these buffers.</p></blockquote><h3 id="Disable-TX-complete-interrupt-by-default">Disable TX complete interrupt by default</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">virtqueue_disable_cb(vrp-&gt;svq);</span><br></pre></td></tr></table></figure><p>Because most of the time, the sender does not need to receive an interrupt every time a TX buffer is consumed by the remote end. Only when Linux has no TX buffers and the sender needs to sleep and wait, is the TX complete interrupt temporarily enabled.</p><h3 id="Create-name-service-endpoint">Create name service endpoint</h3><p>If the remote end supports:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">VIRTIO_RPMSG_F_NS</span><br></pre></td></tr></table></figure><p>Then create a name service endpoint with address<code>53</code>:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;ns_ept = __rpmsg_create_ept(vrp, <span class="literal">NULL</span>, rpmsg_ns_cb,</span><br><span class="line">                     vrp, RPMSG_NS_ADDR);</span><br></pre></td></tr></table></figure><p>Address definition:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_NS_ADDR(53)</span></span><br></pre></td></tr></table></figure><p>This endpoint is specifically for handling remote service creation/destruction notifications.</p><h3 id="Device-ready-and-notify-remote-end">Device ready and notify remote end</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">notify = virtqueue_kick_prepare(vrp-&gt;rvq);</span><br><span class="line">virtio_device_ready(vdev);</span><br><span class="line"><span class="keyword">if</span> (notify)</span><br><span class="line">    virtqueue_notify(vrp-&gt;rvq);</span><br></pre></td></tr></table></figure><p>The order here is important:</p><ol><li>RX buffer is ready (<code>virtqueue_kick_prepare</code>)</li><li>Set virtio device to ready</li><li>Notify remote end that it can start sending messages</li></ol><p>Finally print:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dev_info(&amp;vdev-&gt;dev, <span class="string">&quot;rpmsg host is online\n&quot;</span>);</span><br></pre></td></tr></table></figure><h2 id="remove-function">remove function</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_remove_device</span><span class="params">(<span class="keyword">struct</span> device *dev, <span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">    device_unregister(dev);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">rpmsg_remove</span><span class="params">(<span class="keyword">struct</span> virtio_device *vdev)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span> =</span> vdev-&gt;priv;</span><br><span class="line">    <span class="type">size_t</span> total_buf_space = vrp-&gt;num_bufs * vrp-&gt;buf_size;</span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    vdev-&gt;config-&gt;reset(vdev);</span><br><span class="line"></span><br><span class="line">    ret = device_for_each_child(&amp;vdev-&gt;dev, <span class="literal">NULL</span>, rpmsg_remove_device);</span><br><span class="line">    <span class="keyword">if</span> (ret)</span><br><span class="line">        dev_warn(&amp;vdev-&gt;dev, <span class="string">&quot;can&#x27;t remove rpmsg device: %d\n&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (vrp-&gt;ns_ept)</span><br><span class="line">        __rpmsg_destroy_ept(vrp, vrp-&gt;ns_ept);</span><br><span class="line"></span><br><span class="line">    idr_destroy(&amp;vrp-&gt;endpoints);</span><br><span class="line"></span><br><span class="line">    vdev-&gt;config-&gt;del_vqs(vrp-&gt;vdev);</span><br><span class="line"></span><br><span class="line">    dma_free_coherent(vdev-&gt;dev.parent, total_buf_space,</span><br><span class="line">              vrp-&gt;rbufs, vrp-&gt;bufs_dma);</span><br><span class="line"></span><br><span class="line">    kfree(vrp);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Procedure:</p><ol><li>reset virtio device</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vdev-&gt;config-&gt;reset(vdev);</span><br></pre></td></tr></table></figure><p>First stop the device to avoid further sending and receiving.</p><ol start="2"><li>Delete all child rpmsg devices</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">device_for_each_child(&amp;vdev-&gt;dev, <span class="literal">NULL</span>, rpmsg_remove_device);</span><br></pre></td></tr></table></figure><p>In<code>rpmsg_remove_device()</code>call:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">device_unregister(dev);</span><br></pre></td></tr></table></figure><ol start="3"><li>Destroy NS endpoint</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (vrp-&gt;ns_ept)</span><br><span class="line">    __rpmsg_destroy_ept(vrp, vrp-&gt;ns_ept);</span><br></pre></td></tr></table></figure><ol start="4"><li>endpoints、virtqueue、DMA buffer、vrp</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">idr_destroy(&amp;vrp-&gt;endpoints);</span><br><span class="line">vdev-&gt;config-&gt;del_vqs(vrp-&gt;vdev);</span><br><span class="line">dma_free_coherent(...);</span><br><span class="line">kfree(vrp);</span><br></pre></td></tr></table></figure><h2 id="Send-message-rpmsg-send-offchannel-raw">Send message (<code>rpmsg_send_offchannel_raw()</code>)</h2><p>All send APIs eventually enter<code>rpmsg_send_offchannel_raw()</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * rpmsg_send_offchannel_raw() - send a message across to the remote processor</span></span><br><span class="line"><span class="comment"> * @rpdev: the rpmsg channel</span></span><br><span class="line"><span class="comment"> * @src: source address</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> * @data: payload of message</span></span><br><span class="line"><span class="comment"> * @len: length of payload</span></span><br><span class="line"><span class="comment"> * @wait: indicates whether caller should block in case no TX buffers available</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This function is the base implementation for all of the rpmsg sending API.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * It will send @data of length @len to @dst, and say it&#x27;s from @src. The</span></span><br><span class="line"><span class="comment"> * message will be sent to the remote processor which the @rpdev channel</span></span><br><span class="line"><span class="comment"> * belongs to.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * The message is sent using one of the TX buffers that are available for</span></span><br><span class="line"><span class="comment"> * communication with this remote processor.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If @wait is true, the caller will be blocked until either a TX buffer is</span></span><br><span class="line"><span class="comment"> * available, or 15 seconds elapses (we don&#x27;t want callers to</span></span><br><span class="line"><span class="comment"> * sleep indefinitely due to misbehaving remote processors), and in that</span></span><br><span class="line"><span class="comment"> * case -ERESTARTSYS is returned. The number &#x27;15&#x27; itself was picked</span></span><br><span class="line"><span class="comment"> * arbitrarily; there&#x27;s little point in asking drivers to provide a timeout</span></span><br><span class="line"><span class="comment"> * value themselves.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Otherwise, if @wait is false, and there are no TX buffers available,</span></span><br><span class="line"><span class="comment"> * the function will immediately fail, and -ENOMEM will be returned.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Normally drivers shouldn&#x27;t use this function directly; instead, drivers</span></span><br><span class="line"><span class="comment"> * should use the appropriate rpmsg_&#123;try&#125;send&#123;to, _offchannel&#125; API</span></span><br><span class="line"><span class="comment"> * (see include/linux/rpmsg.h).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Returns 0 on success and an appropriate error value on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_send_offchannel_raw</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev,</span></span><br><span class="line"><span class="params">                     u32 src, u32 dst,</span></span><br><span class="line"><span class="params">                     <span class="type">void</span> *data, <span class="type">int</span> len, <span class="type">bool</span> wait)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtio_rpmsg_channel</span> *<span class="title">vch</span> =</span> to_virtio_rpmsg_channel(rpdev);</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span> =</span> vch-&gt;vrp;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span> =</span> &amp;rpdev-&gt;dev;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">scatterlist</span> <span class="title">sg</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_hdr</span> *<span class="title">msg</span>;</span></span><br><span class="line">    <span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* bcasting isn&#x27;t allowed */</span></span><br><span class="line">    <span class="keyword">if</span> (src == RPMSG_ADDR_ANY || dst == RPMSG_ADDR_ANY) &#123;</span><br><span class="line">        dev_err(dev, <span class="string">&quot;invalid addr (src 0x%x, dst 0x%x)\n&quot;</span>, src, dst);</span><br><span class="line">        <span class="keyword">return</span> -EINVAL;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * We currently use fixed-sized buffers, and therefore the payload</span></span><br><span class="line"><span class="comment">     * length is limited.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * One of the possible improvements here is either to support</span></span><br><span class="line"><span class="comment">     * user-provided buffers (and then we can also support zero-copy</span></span><br><span class="line"><span class="comment">     * messaging), or to improve the buffer allocator, to support</span></span><br><span class="line"><span class="comment">     * variable-length buffer sizes.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (len &gt; vrp-&gt;buf_size - <span class="keyword">sizeof</span>(<span class="keyword">struct</span> rpmsg_hdr)) &#123;</span><br><span class="line">        dev_err(dev, <span class="string">&quot;message is too big (%d)\n&quot;</span>, len);</span><br><span class="line">        <span class="keyword">return</span> -EMSGSIZE;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* grab a buffer */</span></span><br><span class="line">    msg = get_a_tx_buf(vrp);</span><br><span class="line">    <span class="keyword">if</span> (!msg &amp;&amp; !wait)</span><br><span class="line">        <span class="keyword">return</span> -ENOMEM;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* no free buffer ? wait for one (but bail after 15 seconds) */</span></span><br><span class="line">    <span class="keyword">while</span> (!msg) &#123;</span><br><span class="line">        <span class="comment">/* enable &quot;tx-complete&quot; interrupts, if not already enabled */</span></span><br><span class="line">        rpmsg_upref_sleepers(vrp);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * sleep until a free buffer is available or 15 secs elapse.</span></span><br><span class="line"><span class="comment">         * the timeout period is not configurable because there&#x27;s</span></span><br><span class="line"><span class="comment">         * little point in asking drivers to specify that.</span></span><br><span class="line"><span class="comment">         * if later this happens to be required, it&#x27;d be easy to add.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        err = wait_event_interruptible_timeout(vrp-&gt;sendq,</span><br><span class="line">                    (msg = get_a_tx_buf(vrp)),</span><br><span class="line">                    msecs_to_jiffies(<span class="number">15000</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* disable &quot;tx-complete&quot; interrupts if we&#x27;re the last sleeper */</span></span><br><span class="line">        rpmsg_downref_sleepers(vrp);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* timeout ? */</span></span><br><span class="line">        <span class="keyword">if</span> (!err) &#123;</span><br><span class="line">            dev_err(dev, <span class="string">&quot;timeout waiting for a tx buffer\n&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> -ERESTARTSYS;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    msg-&gt;len = cpu_to_virtio16(vrp-&gt;vdev, len);</span><br><span class="line">    msg-&gt;flags = <span class="number">0</span>;</span><br><span class="line">    msg-&gt;src = cpu_to_virtio32(vrp-&gt;vdev, src);</span><br><span class="line">    msg-&gt;dst = cpu_to_virtio32(vrp-&gt;vdev, dst);</span><br><span class="line">    msg-&gt;reserved = <span class="number">0</span>;</span><br><span class="line">    <span class="built_in">memcpy</span>(msg-&gt;data, data, len);</span><br><span class="line"></span><br><span class="line">    dev_dbg(dev, <span class="string">&quot;TX From 0x%x, To 0x%x, Len %d, Flags %d, Reserved %d\n&quot;</span>,</span><br><span class="line">        src, dst, len, msg-&gt;flags, msg-&gt;reserved);</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(CONFIG_DYNAMIC_DEBUG)</span></span><br><span class="line">    dynamic_hex_dump(<span class="string">&quot;rpmsg_virtio TX: &quot;</span>, DUMP_PREFIX_NONE, <span class="number">16</span>, <span class="number">1</span>,</span><br><span class="line">             msg, <span class="keyword">sizeof</span>(*msg) + len, <span class="literal">true</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">    rpmsg_sg_init(&amp;sg, msg, <span class="keyword">sizeof</span>(*msg) + len);</span><br><span class="line"></span><br><span class="line">    mutex_lock(&amp;vrp-&gt;tx_lock);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* add message to the remote processor&#x27;s virtqueue */</span></span><br><span class="line">    err = virtqueue_add_outbuf(vrp-&gt;svq, &amp;sg, <span class="number">1</span>, msg, GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (err) &#123;</span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * need to reclaim the buffer here, otherwise it&#x27;s lost</span></span><br><span class="line"><span class="comment">         * (memory won&#x27;t leak, but rpmsg won&#x27;t use it again for TX).</span></span><br><span class="line"><span class="comment">         * this will wait for a buffer management overhaul.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        dev_err(dev, <span class="string">&quot;virtqueue_add_outbuf failed: %d\n&quot;</span>, err);</span><br><span class="line">        <span class="keyword">goto</span> out;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* tell the remote processor it has a pending message to read */</span></span><br><span class="line">    virtqueue_kick(vrp-&gt;svq);</span><br><span class="line">out:</span><br><span class="line">    mutex_unlock(&amp;vrp-&gt;tx_lock);</span><br><span class="line">    <span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>The call chain is roughly:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">rpmsg_send()</span><br><span class="line">  → ept-&gt;ops-&gt;send()</span><br><span class="line">    → virtio_rpmsg_send()</span><br><span class="line">      → rpmsg_send_offchannel_raw()</span><br><span class="line"></span><br><span class="line">rpmsg_trysend()</span><br><span class="line">  → virtio_rpmsg_trysend()</span><br><span class="line">    → rpmsg_send_offchannel_raw(..., wait = false)</span><br></pre></td></tr></table></figure><h3 id="Parameter-check">Parameter check</h3><p>First check src/dst:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (src == RPMSG_ADDR_ANY || dst == RPMSG_ADDR_ANY)</span><br><span class="line">    <span class="keyword">return</span> -EINVAL;</span><br></pre></td></tr></table></figure><p>Broadcast addresses are not allowed as actual send addresses.<br>Then check the length:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (len &gt; vrp-&gt;buf_size - <span class="keyword">sizeof</span>(<span class="keyword">struct</span> rpmsg_hdr))</span><br><span class="line">    <span class="keyword">return</span> -EMSGSIZE;</span><br></pre></td></tr></table></figure><p>Because a single buffer is fixed at 512 bytes, the payload cannot exceed<code>512 - sizeof(struct rpmsg_hdr)</code></p><h3 id="Get-TX-buffer">Get TX buffer</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">msg = get_a_tx_buf(vrp);</span><br></pre></td></tr></table></figure><p>Its logic:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (vrp-&gt;last_sbuf &lt; vrp-&gt;num_bufs / <span class="number">2</span>)</span><br><span class="line">    ret = vrp-&gt;sbufs + vrp-&gt;buf_size * vrp-&gt;last_sbuf++;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    ret = virtqueue_get_buf(vrp-&gt;svq, &amp;len);</span><br></pre></td></tr></table></figure><p>Meaning:</p><ol><li>Initial stage: directly take an unused buffer from the TX buffer pool</li><li>Subsequent stage: from the<code>svq</code>used ring, reclaim TX buffers that have been consumed by the remote end</li></ol><h3 id="What-to-do-when-there-is-no-TX-buffer">What to do when there is no TX buffer?</h3><p>If it is<code>trysend</code>：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (!msg &amp;&amp; !wait)</span><br><span class="line">    <span class="keyword">return</span> -ENOMEM;</span><br></pre></td></tr></table></figure><p>If it is normal<code>send</code>, then wait, up to 15 seconds:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">err = wait_event_interruptible_timeout(vrp-&gt;sendq,</span><br><span class="line">            (msg = get_a_tx_buf(vrp)),</span><br><span class="line">            msecs_to_jiffies(<span class="number">15000</span>));</span><br></pre></td></tr></table></figure><p>If timeout:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">return</span> -ERESTARTSYS;</span><br></pre></td></tr></table></figure><p>Before waiting, it will call:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpmsg_upref_sleepers(vrp);</span><br></pre></td></tr></table></figure><p>Function: If this is the first sender sleeping and waiting for a TX buffer, enable the TX complete interrupt</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">virtqueue_enable_cb(vrp-&gt;svq);</span><br></pre></td></tr></table></figure><p>After waiting ends, it will call:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpmsg_downref_sleepers(vrp);</span><br></pre></td></tr></table></figure><p>If there are no more waiters, disable the TX complete interrupt:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">virtqueue_disable_cb(vrp-&gt;svq);</span><br></pre></td></tr></table></figure><h3 id="Fill-the-rpmsg-header-and-payload">Fill the rpmsg header and payload</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">msg-&gt;len = cpu_to_virtio16(vrp-&gt;vdev, len);</span><br><span class="line">msg-&gt;flags = <span class="number">0</span>;</span><br><span class="line">msg-&gt;src = cpu_to_virtio32(vrp-&gt;vdev, src);</span><br><span class="line">msg-&gt;dst = cpu_to_virtio32(vrp-&gt;vdev, dst);</span><br><span class="line">msg-&gt;reserved = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">memcpy</span>(msg-&gt;data, data, len);</span><br></pre></td></tr></table></figure><p>Note that here we use<code>cpu_to_virtio16/32()</code>, because virtio devices may have specific endianness requirements.</p><h3 id="Add-to-the-TX-virtqueue-and-kick-the-remote-side">Add to the TX virtqueue and kick the remote side</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">virtqueue_add_outbuf(vrp-&gt;svq, &amp;sg, <span class="number">1</span>, msg, GFP_KERNEL);</span><br></pre></td></tr></table></figure><p>Then:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">virtqueue_kick(vrp-&gt;svq);</span><br></pre></td></tr></table></figure><p>Full meaning:<br>Linux fills the TX buffer → adds the buffer to the output virtqueue → kicks the remote processor → the remote side takes the message from the virtqueue</p><h3 id="TX-complete-callback">TX complete callback</h3><p>Set in the probe function</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_probe</span><span class="params">(<span class="keyword">struct</span> virtio_device *vdev)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">vq_callback_t</span> *vq_cbs[] = &#123; rpmsg_recv_done, rpmsg_xmit_done &#125;;</span><br><span class="line">    <span class="type">static</span> <span class="type">const</span> <span class="type">char</span> * <span class="type">const</span> names[] = &#123; <span class="string">&quot;input&quot;</span>, <span class="string">&quot;output&quot;</span> &#125;;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtqueue</span> *<span class="title">vqs</span>[2];</span></span><br><span class="line">    </span><br><span class="line">    .....</span><br><span class="line">    </span><br><span class="line">    err = virtio_find_vqs(vdev, <span class="number">2</span>, vqs, vq_cbs, names, <span class="literal">NULL</span>);</span><br><span class="line">    </span><br><span class="line">    .....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>That is, the TX callback function is<code>rpmsg_xmit_done</code></p><blockquote><p>Note: Normally, the TX complete interrupt is disabled; it is only enabled when a sender is sleeping and waiting for a buffer.</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * This is invoked whenever the remote processor completed processing</span></span><br><span class="line"><span class="comment"> * a TX msg we just sent it, and the buffer is put back to the used ring.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Normally, though, we suppress this &quot;tx complete&quot; interrupt in order to</span></span><br><span class="line"><span class="comment"> * avoid the incurred overhead.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">rpmsg_xmit_done</span><span class="params">(<span class="keyword">struct</span> virtqueue *svq)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span> =</span> svq-&gt;vdev-&gt;priv;</span><br><span class="line"></span><br><span class="line">    dev_dbg(&amp;svq-&gt;vdev-&gt;dev, <span class="string">&quot;%s\n&quot;</span>, __func__);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* wake up potential senders that are waiting for a tx buffer */</span></span><br><span class="line">    wake_up_interruptible(&amp;vrp-&gt;sendq);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>When the remote end consumes the TX buffer, the virtio backend places the buffer into the used ring and triggers the TX complete callback. Linux wakes up the sending thread waiting for the TX buffer.</p><h4 id="TX-sleepers-mechanism-rpmsg-upref-sleepers">TX sleepers mechanism:<code>rpmsg_upref_sleepers()</code></h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">rpmsg_upref_sleepers</span><span class="params">(<span class="keyword">struct</span> virtproc_info *vrp)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">/* support multiple concurrent senders */</span></span><br><span class="line">    mutex_lock(&amp;vrp-&gt;tx_lock);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* are we the first sleeping context waiting for tx buffers ? */</span></span><br><span class="line">    <span class="keyword">if</span> (atomic_inc_return(&amp;vrp-&gt;sleepers) == <span class="number">1</span>)</span><br><span class="line">        <span class="comment">/* enable &quot;tx-complete&quot; interrupts before dozing off */</span></span><br><span class="line">        virtqueue_enable_cb(vrp-&gt;svq);</span><br><span class="line"></span><br><span class="line">    mutex_unlock(&amp;vrp-&gt;tx_lock);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Meaning: Before a sending thread prepares to sleep due to lack of TX buffer:<code>sleepers++</code>, if this is the first waiter, enable the TX complete callback<br>Correspondingly, there is also<code>rpmsg_downref_sleepers()</code>: After the sending thread wakes up:<code>sleepers--</code>, if this is the last waiter, disable the TX complete callback</p><p>Purpose of this mechanism:</p><ul><li>No one waiting for TX buffer: disable TX complete interrupt to reduce overhead</li><li>Someone waiting for TX buffer: enable TX complete interrupt to immediately wake up the waiter when the remote end returns the buffer</li></ul><p>Complete chain:</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">TX buffer 用完</span><br><span class="line">    ↓</span><br><span class="line">rpmsg<span class="built_in">_</span>send() 准备睡眠</span><br><span class="line">    ↓</span><br><span class="line">rpmsg<span class="built_in">_</span>upref<span class="built_in">_</span>sleepers()</span><br><span class="line">    ↓</span><br><span class="line">第一个 sleeper 打开 svq callback</span><br><span class="line">    ↓</span><br><span class="line">远端读完 TX buffer</span><br><span class="line">    ↓</span><br><span class="line">rpmsg<span class="built_in">_</span>xmit<span class="built_in">_</span>done()</span><br><span class="line">    ↓</span><br><span class="line">wake<span class="built_in">_</span>up<span class="built_in">_</span>interruptible(<span class="built_in">&amp;</span>vrp-&gt;sendq)</span><br><span class="line">    ↓</span><br><span class="line">发送线程醒来</span><br><span class="line">    ↓</span><br><span class="line">get<span class="built_in">_</span>a<span class="built_in">_</span>tx<span class="built_in">_</span>buf() / virtqueue<span class="built_in">_</span>get<span class="built_in">_</span>buf(svq)</span><br><span class="line">    ↓</span><br><span class="line">拿到回收 buffer</span><br></pre></td></tr></table></figure><h2 id="Receive-message-rpmsg-recv-done">Receive message (<code>rpmsg_recv_done</code>)</h2><p>Set in the probe function</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_probe</span><span class="params">(<span class="keyword">struct</span> virtio_device *vdev)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">vq_callback_t</span> *vq_cbs[] = &#123; rpmsg_recv_done, rpmsg_xmit_done &#125;;</span><br><span class="line">    <span class="type">static</span> <span class="type">const</span> <span class="type">char</span> * <span class="type">const</span> names[] = &#123; <span class="string">&quot;input&quot;</span>, <span class="string">&quot;output&quot;</span> &#125;;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtqueue</span> *<span class="title">vqs</span>[2];</span></span><br><span class="line">    </span><br><span class="line">    .....</span><br><span class="line">    </span><br><span class="line">    err = virtio_find_vqs(vdev, <span class="number">2</span>, vqs, vq_cbs, names, <span class="literal">NULL</span>);</span><br><span class="line">    </span><br><span class="line">    .....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>That is, the rx callback function is<code>rpmsg_recv_done</code>, the function is defined as follows:</p><h3 id="rpmsg-recv-done"><code>rpmsg_recv_done</code></h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* called when an rx buffer is used, and it&#x27;s time to digest a message */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">rpmsg_recv_done</span><span class="params">(<span class="keyword">struct</span> virtqueue *rvq)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span> =</span> rvq-&gt;vdev-&gt;priv;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span> =</span> &amp;rvq-&gt;vdev-&gt;dev;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_hdr</span> *<span class="title">msg</span>;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> len, msgs_received = <span class="number">0</span>;</span><br><span class="line">    <span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">    msg = virtqueue_get_buf(rvq, &amp;len);</span><br><span class="line">    <span class="keyword">if</span> (!msg) &#123;</span><br><span class="line">        dev_err(dev, <span class="string">&quot;uhm, incoming signal, but no used buffer ?\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (msg) &#123;</span><br><span class="line">        err = rpmsg_recv_single(vrp, dev, msg, len);</span><br><span class="line">        <span class="keyword">if</span> (err)</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line">        msgs_received++;</span><br><span class="line"></span><br><span class="line">        msg = virtqueue_get_buf(rvq, &amp;len);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    dev_dbg(dev, <span class="string">&quot;Received %u messages\n&quot;</span>, msgs_received);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* tell the remote processor we added another available rx buffer */</span></span><br><span class="line">    <span class="keyword">if</span> (msgs_received)</span><br><span class="line">        virtqueue_kick(vrp-&gt;rvq);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Take-used-buffer-from-RX-virtqueue">Take used buffer from RX virtqueue</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">msg = virtqueue_get_buf(rvq, &amp;len);</span><br></pre></td></tr></table></figure><p>If a msg is obtained, try to continue and loop through all available messages:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> (msg) &#123;</span><br><span class="line">    err = rpmsg_recv_single(vrp, dev, msg, len);</span><br><span class="line">    <span class="keyword">if</span> (err)</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line">    msgs_received++;</span><br><span class="line"></span><br><span class="line">    msg = virtqueue_get_buf(rvq, &amp;len);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Single-message-processing-rpmsg-recv-single">Single message processing:<code>rpmsg_recv_single()</code></h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_recv_single</span><span class="params">(<span class="keyword">struct</span> virtproc_info *vrp, <span class="keyword">struct</span> device *dev,</span></span><br><span class="line"><span class="params">                 <span class="keyword">struct</span> rpmsg_hdr *msg, <span class="type">unsigned</span> <span class="type">int</span> len)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_endpoint</span> *<span class="title">ept</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">scatterlist</span> <span class="title">sg</span>;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> msg_len = virtio16_to_cpu(vrp-&gt;vdev, msg-&gt;len);</span><br><span class="line">    <span class="type">int</span> err;</span><br><span class="line"></span><br><span class="line">    dev_dbg(dev, <span class="string">&quot;From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d\n&quot;</span>,</span><br><span class="line">        virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;src),</span><br><span class="line">        virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;dst), msg_len,</span><br><span class="line">        virtio16_to_cpu(vrp-&gt;vdev, msg-&gt;flags),</span><br><span class="line">        virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;reserved));</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(CONFIG_DYNAMIC_DEBUG)</span></span><br><span class="line">    dynamic_hex_dump(<span class="string">&quot;rpmsg_virtio RX: &quot;</span>, DUMP_PREFIX_NONE, <span class="number">16</span>, <span class="number">1</span>,</span><br><span class="line">             msg, <span class="keyword">sizeof</span>(*msg) + msg_len, <span class="literal">true</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * We currently use fixed-sized buffers, so trivially sanitize</span></span><br><span class="line"><span class="comment">     * the reported payload length.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (len &gt; vrp-&gt;buf_size ||</span><br><span class="line">        msg_len &gt; (len - <span class="keyword">sizeof</span>(<span class="keyword">struct</span> rpmsg_hdr))) &#123;</span><br><span class="line">        dev_warn(dev, <span class="string">&quot;inbound msg too big: (%d, %d)\n&quot;</span>, len, msg_len);</span><br><span class="line">        <span class="keyword">return</span> -EINVAL;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* use the dst addr to fetch the callback of the appropriate user */</span></span><br><span class="line">    mutex_lock(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line"></span><br><span class="line">    ept = idr_find(&amp;vrp-&gt;endpoints, virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;dst));</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* let&#x27;s make sure no one deallocates ept while we use it */</span></span><br><span class="line">    <span class="keyword">if</span> (ept)</span><br><span class="line">        kref_get(&amp;ept-&gt;refcount);</span><br><span class="line"></span><br><span class="line">    mutex_unlock(&amp;vrp-&gt;endpoints_lock);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (ept) &#123;</span><br><span class="line">        <span class="comment">/* make sure ept-&gt;cb doesn&#x27;t go away while we use it */</span></span><br><span class="line">        mutex_lock(&amp;ept-&gt;cb_lock);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (ept-&gt;cb)</span><br><span class="line">            ept-&gt;cb(ept-&gt;rpdev, msg-&gt;data, msg_len, ept-&gt;priv,</span><br><span class="line">                virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;src));</span><br><span class="line"></span><br><span class="line">        mutex_unlock(&amp;ept-&gt;cb_lock);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* farewell, ept, we don&#x27;t need you anymore */</span></span><br><span class="line">        kref_put(&amp;ept-&gt;refcount, __ept_release);</span><br><span class="line">    &#125; <span class="keyword">else</span></span><br><span class="line">        dev_warn(dev, <span class="string">&quot;msg received with no recipient\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* publish the real size of the buffer */</span></span><br><span class="line">    rpmsg_sg_init(&amp;sg, msg, vrp-&gt;buf_size);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* add the buffer back to the remote processor&#x27;s virtqueue */</span></span><br><span class="line">    err = virtqueue_add_inbuf(vrp-&gt;rvq, &amp;sg, <span class="number">1</span>, msg, GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (err &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        dev_err(dev, <span class="string">&quot;failed to add a virtqueue buffer: %d\n&quot;</span>, err);</span><br><span class="line">        <span class="keyword">return</span> err;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>When receiving, it is not distributed by channel name, but by:<code>msg-&gt;dst</code>, in<code>vrp-&gt;endpoints</code>look up the local endpoint. So rpmsg actually runs more like address-based messaging, and the channel name is mainly used for device discovery and driver matching.<br>Main steps:</p></blockquote><ol><li>Parse payload length</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">msg_len = virtio16_to_cpu(vrp-&gt;vdev, msg-&gt;len);</span><br></pre></td></tr></table></figure><ol start="2"><li>Check if the message length is valid</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (len &gt; vrp-&gt;buf_size ||</span><br><span class="line">    msg_len &gt; (len - <span class="keyword">sizeof</span>(<span class="keyword">struct</span> rpmsg_hdr))) &#123;</span><br><span class="line">    <span class="keyword">return</span> -EINVAL;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Prevent out-of-bounds caused by abnormal length from the remote end.</p><ol start="3"><li>According to<code>dst</code>find the endpoint</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ept = idr_find(&amp;vrp-&gt;endpoints, virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;dst));</span><br></pre></td></tr></table></figure><p>This is the core of rpmsg distribution:<code>msg-&gt;dst == 本地 endpoint 地址</code></p><ol start="4"><li>Increase endpoint reference count</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (ept)</span><br><span class="line">    kref_get(&amp;ept-&gt;refcount);</span><br></pre></td></tr></table></figure><p>Prevent endpoint from being released during callback execution.</p><ol start="5"><li>Call callback</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (ept-&gt;cb)</span><br><span class="line">    ept-&gt;cb(ept-&gt;rpdev, msg-&gt;data, msg_len, ept-&gt;priv,</span><br><span class="line">        virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;src));</span><br></pre></td></tr></table></figure><p>Parameters passed to the upper-layer callback include:</p><div class="table-wrap"><table><thead><tr><th>Parameter</th><th>Meaning</th></tr></thead><tbody><tr><td><code>ept-&gt;rpdev</code></td><td>Corresponding rpmsg device</td></tr><tr><td><code>msg-&gt;data</code></td><td>payload</td></tr><tr><td><code>msg_len</code></td><td>Payload length</td></tr><tr><td><code>ept-&gt;priv</code></td><td>Endpoint private data</td></tr><tr><td><code>msg-&gt;src</code></td><td>Remote source address</td></tr></tbody></table></div><ol start="6"><li>Put RX buffer back into virtqueue<br>After processing, this buffer needs to be reused by the remote side:</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">rpmsg_sg_init(&amp;sg, msg, vrp-&gt;buf_size);</span><br><span class="line">err = virtqueue_add_inbuf(vrp-&gt;rvq, &amp;sg, <span class="number">1</span>, msg, GFP_KERNEL);</span><br></pre></td></tr></table></figure><h4 id="Kick-remote">Kick remote</h4><p>Finally, in<code>rpmsg_recv_done()</code>If a message has been processed inside, kick the remote end:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (msgs_received)</span><br><span class="line">    virtqueue_kick(vrp-&gt;rvq);</span><br></pre></td></tr></table></figure><h2 id="Name-service-mechanism">Name service mechanism</h2><blockquote><p>Note: name service is an optional feature. Feature definition:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> VIRTIO_RPMSG_F_NS0</span></span><br></pre></td></tr></table></figure><p>If the remote end does not support this feature, dynamic service discovery is unavailable. In this case, the channel may need to be created statically.</p></blockquote><p>rpmsg supports the remote end dynamically notifying Linux: I created a service or I destroyed a service, this is called name service. Related structure:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ns_msg</span> &#123;</span></span><br><span class="line">    <span class="type">char</span> name[RPMSG_NAME_SIZE];</span><br><span class="line">    __virtio32 addr;</span><br><span class="line">    __virtio32 flags;</span><br><span class="line">&#125; __packed;</span><br></pre></td></tr></table></figure><p>Fields:</p><div class="table-wrap"><table><thead><tr><th>Field</th><th>Meaning</th></tr></thead><tbody><tr><td><code>name</code></td><td>Service name</td></tr><tr><td><code>addr</code></td><td>Remote service address</td></tr><tr><td><code>flags</code></td><td>Create or destroy</td></tr></tbody></table></div><p>flags：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">RPMSG_NS_CREATE  = <span class="number">0</span></span><br><span class="line">RPMSG_NS_DESTROY = <span class="number">1</span></span><br></pre></td></tr></table></figure><h3 id="NS-endpoint">NS endpoint</h3><p>Name service uses a fixed address:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> RPMSG_NS_ADDR(53)</span></span><br></pre></td></tr></table></figure><p>Created during probe:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vrp-&gt;ns_ept = __rpmsg_create_ept(vrp, <span class="literal">NULL</span>, rpmsg_ns_cb,</span><br><span class="line">                     vrp, RPMSG_NS_ADDR);</span><br></pre></td></tr></table></figure><p>Note here<code>rpdev</code>The parameter is<code>NULL</code>, because the NS endpoint does not belong to a regular rpmsg channel, but is an internal endpoint used by the bus itself.</p><h3 id="NS-callback：rpmsg-ns-cb">NS callback：<code>rpmsg_ns_cb()</code></h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* invoked when a name service announcement arrives */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">rpmsg_ns_cb</span><span class="params">(<span class="keyword">struct</span> rpmsg_device *rpdev, <span class="type">void</span> *data, <span class="type">int</span> len,</span></span><br><span class="line"><span class="params">               <span class="type">void</span> *priv, u32 src)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_ns_msg</span> *<span class="title">msg</span> =</span> data;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">newch</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> <span class="title">chinfo</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span> =</span> priv;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">dev</span> =</span> &amp;vrp-&gt;vdev-&gt;dev;</span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(CONFIG_DYNAMIC_DEBUG)</span></span><br><span class="line">    dynamic_hex_dump(<span class="string">&quot;NS announcement: &quot;</span>, DUMP_PREFIX_NONE, <span class="number">16</span>, <span class="number">1</span>,</span><br><span class="line">             data, len, <span class="literal">true</span>);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (len != <span class="keyword">sizeof</span>(*msg)) &#123;</span><br><span class="line">        dev_err(dev, <span class="string">&quot;malformed ns msg (%d)\n&quot;</span>, len);</span><br><span class="line">        <span class="keyword">return</span> -EINVAL;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * the name service ept does _not_ belong to a real rpmsg channel,</span></span><br><span class="line"><span class="comment">     * and is handled by the rpmsg bus itself.</span></span><br><span class="line"><span class="comment">     * for sanity reasons, make sure a valid rpdev has _not_ sneaked</span></span><br><span class="line"><span class="comment">     * in somehow.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (rpdev) &#123;</span><br><span class="line">        dev_err(dev, <span class="string">&quot;anomaly: ns ept has an rpdev handle\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> -EINVAL;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* don&#x27;t trust the remote processor for null terminating the name */</span></span><br><span class="line">    msg-&gt;name[RPMSG_NAME_SIZE - <span class="number">1</span>] = <span class="string">&#x27;\0&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">strncpy</span>(chinfo.name, msg-&gt;name, <span class="keyword">sizeof</span>(chinfo.name));</span><br><span class="line">    chinfo.src = RPMSG_ADDR_ANY;</span><br><span class="line">    chinfo.dst = virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;addr);</span><br><span class="line"></span><br><span class="line">    dev_info(dev, <span class="string">&quot;%sing channel %s addr 0x%x\n&quot;</span>,</span><br><span class="line">         virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;flags) &amp; RPMSG_NS_DESTROY ?</span><br><span class="line">         <span class="string">&quot;destroy&quot;</span> : <span class="string">&quot;creat&quot;</span>, msg-&gt;name, chinfo.dst);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (virtio32_to_cpu(vrp-&gt;vdev, msg-&gt;flags) &amp; RPMSG_NS_DESTROY) &#123;</span><br><span class="line">        ret = rpmsg_unregister_device(&amp;vrp-&gt;vdev-&gt;dev, &amp;chinfo);</span><br><span class="line">        <span class="keyword">if</span> (ret)</span><br><span class="line">            dev_err(dev, <span class="string">&quot;rpmsg_destroy_channel failed: %d\n&quot;</span>, ret);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        newch = rpmsg_create_channel(vrp, &amp;chinfo);</span><br><span class="line">        <span class="keyword">if</span> (!newch)</span><br><span class="line">            dev_err(dev, <span class="string">&quot;rpmsg_create_channel failed\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>After receiving a remote NS message:</p><ol><li>Check length</li><li>Ensure the endpoint is not bound to a real<code>rpdev</code></li><li>Fix the end of the name string</li><li>Construct<code>rpmsg_channel_info</code></li><li>Create or destroy a channel based on flags</li></ol><p>Create channel:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">newch = rpmsg_create_channel(vrp, &amp;chinfo);</span><br></pre></td></tr></table></figure><p>Destroy channel:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ret = rpmsg_unregister_device(&amp;vrp-&gt;vdev-&gt;dev, &amp;chinfo);</span><br></pre></td></tr></table></figure><h3 id="Local-service-announce-mechanism">Local service announce mechanism</h3><p>This driver can not only receive remote NS, but also announce local services to the remote end.</p><p>Related functions:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">virtio_rpmsg_announce_create()</span><br><span class="line">virtio_rpmsg_announce_destroy()</span><br></pre></td></tr></table></figure><p>When a local rpmsg channel that needs to be announced is created, the driver constructs<code>rpmsg_ns_msg</code>, and sends it to the remote NS address<code>53</code>(at<code>rpmsg_core.c</code>). Create notification:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nsm.flags = cpu_to_virtio32(vrp-&gt;vdev, RPMSG_NS_CREATE);</span><br><span class="line">err = rpmsg_sendto(rpdev-&gt;ept, &amp;nsm, <span class="keyword">sizeof</span>(nsm), RPMSG_NS_ADDR);</span><br></pre></td></tr></table></figure><p>Destroy notification:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">nsm.flags = cpu_to_virtio32(vrp-&gt;vdev, RPMSG_NS_DESTROY);</span><br><span class="line">err = rpmsg_sendto(rpdev-&gt;ept, &amp;nsm, <span class="keyword">sizeof</span>(nsm), RPMSG_NS_ADDR);</span><br></pre></td></tr></table></figure><h2 id="rpmsg-channel-creation">rpmsg channel creation</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * create an rpmsg channel using its name and address info.</span></span><br><span class="line"><span class="comment"> * this function will be used to create both static and dynamic</span></span><br><span class="line"><span class="comment"> * channels.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> rpmsg_device *<span class="title function_">rpmsg_create_channel</span><span class="params">(<span class="keyword">struct</span> virtproc_info *vrp,</span></span><br><span class="line"><span class="params">                         <span class="keyword">struct</span> rpmsg_channel_info *chinfo)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtio_rpmsg_channel</span> *<span class="title">vch</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> *<span class="title">rpdev</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">device</span> *<span class="title">tmp</span>, *<span class="title">dev</span> =</span> &amp;vrp-&gt;vdev-&gt;dev;</span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* make sure a similar channel doesn&#x27;t already exist */</span></span><br><span class="line">    tmp = rpmsg_find_device(dev, chinfo);</span><br><span class="line">    <span class="keyword">if</span> (tmp) &#123;</span><br><span class="line">        <span class="comment">/* decrement the matched device&#x27;s refcount back */</span></span><br><span class="line">        put_device(tmp);</span><br><span class="line">        dev_err(dev, <span class="string">&quot;channel %s:%x:%x already exist\n&quot;</span>,</span><br><span class="line">                chinfo-&gt;name, chinfo-&gt;src, chinfo-&gt;dst);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    vch = kzalloc(<span class="keyword">sizeof</span>(*vch), GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (!vch)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Link the channel to our vrp */</span></span><br><span class="line">    vch-&gt;vrp = vrp;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Assign public information to the rpmsg_device */</span></span><br><span class="line">    rpdev = &amp;vch-&gt;rpdev;</span><br><span class="line">    rpdev-&gt;src = chinfo-&gt;src;</span><br><span class="line">    rpdev-&gt;dst = chinfo-&gt;dst;</span><br><span class="line">    rpdev-&gt;ops = &amp;virtio_rpmsg_ops;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * rpmsg server channels has predefined local address (for now),</span></span><br><span class="line"><span class="comment">     * and their existence needs to be announced remotely</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    rpdev-&gt;announce = rpdev-&gt;src != RPMSG_ADDR_ANY;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">strncpy</span>(rpdev-&gt;id.name, chinfo-&gt;name, RPMSG_NAME_SIZE);</span><br><span class="line"></span><br><span class="line">    rpdev-&gt;dev.parent = &amp;vrp-&gt;vdev-&gt;dev;</span><br><span class="line">    rpdev-&gt;dev.release = virtio_rpmsg_release_device;</span><br><span class="line">    ret = rpmsg_register_device(rpdev);</span><br><span class="line">    <span class="keyword">if</span> (ret)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> rpdev;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>It, based on the incoming<code>struct rpmsg_channel_info *chinfo</code>create a<code>rpmsg_device</code>。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct rpmsg_channel_info - channel info representation</span></span><br><span class="line"><span class="comment"> * @name: name of service</span></span><br><span class="line"><span class="comment"> * @src: local address</span></span><br><span class="line"><span class="comment"> * @dst: destination address</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_channel_info</span> &#123;</span></span><br><span class="line">    <span class="type">char</span> name[RPMSG_NAME_SIZE];</span><br><span class="line">    u32 src;</span><br><span class="line">    u32 dst;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Process:</p><ol><li>Check if the same channel already exists</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tmp = rpmsg_find_device(dev, chinfo);</span><br></pre></td></tr></table></figure><p>If it already exists, do not create it again.</p><ol start="2"><li>Allocate<code>virtio_rpmsg_channel</code></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vch = kzalloc(<span class="keyword">sizeof</span>(*vch), GFP_KERNEL);</span><br></pre></td></tr></table></figure><p>this structure:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">virtio_rpmsg_channel</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rpmsg_device</span> <span class="title">rpdev</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">virtproc_info</span> *<span class="title">vrp</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>It is a virtio transport private channel, exposing the<code>rpmsg_device</code>。</p><ol start="3"><li>Fill<code>rpmsg_device</code></li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">rpdev-&gt;src = chinfo-&gt;src;</span><br><span class="line">rpdev-&gt;dst = chinfo-&gt;dst;</span><br><span class="line">rpdev-&gt;ops = &amp;virtio_rpmsg_ops;</span><br><span class="line"></span><br><span class="line"><span class="built_in">strncpy</span>(rpdev-&gt;id.name, chinfo-&gt;name, RPMSG_NAME_SIZE);</span><br></pre></td></tr></table></figure><p>Then register:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ret = rpmsg_register_device(rpdev);</span><br></pre></td></tr></table></figure><p>After registration, the rpmsg bus will match the id table of the upper-layer rpmsg driver, and then call the probe of the corresponding driver.</p><h2 id="Overall-send-receive-flow-diagram">Overall send/receive flow diagram</h2><h3 id="Linux-sends-a-message-to-the-remote-end">Linux sends a message to the remote end</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">上层 rpmsg driver</span><br><span class="line">    |</span><br><span class="line">    | rpmsg_send()</span><br><span class="line">    v</span><br><span class="line">rpmsg core</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">virtio_rpmsg_send()</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">rpmsg_send_offchannel_raw()</span><br><span class="line">    |</span><br><span class="line">    | 1. 检查 src/dst/len</span><br><span class="line">    | 2. 获取 TX buffer</span><br><span class="line">    | 3. 填 rpmsg_hdr</span><br><span class="line">    | 4. memcpy payload</span><br><span class="line">    | 5. virtqueue_add_outbuf()</span><br><span class="line">    | 6. virtqueue_kick()</span><br><span class="line">    v</span><br><span class="line">远端处理器从 svq 取消息</span><br></pre></td></tr></table></figure><h3 id="Linux-receives-a-message-from-the-remote-end">Linux receives a message from the remote end</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">远端处理器写入 RX buffer</span><br><span class="line">    |</span><br><span class="line">    | 通知 virtqueue</span><br><span class="line">    v</span><br><span class="line">rpmsg_recv_done()</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">virtqueue_get_buf()</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">rpmsg_recv_single()</span><br><span class="line">    |</span><br><span class="line">    | 1. 检查长度</span><br><span class="line">    | 2. 用 msg-&gt;dst 查 endpoint</span><br><span class="line">    | 3. 调 endpoint callback</span><br><span class="line">    | 4. 把 RX buffer 重新 add_inbuf()</span><br><span class="line">    v</span><br><span class="line">上层 rpmsg driver 收到 callback</span><br></pre></td></tr></table></figure><h3 id="Remote-end-publishes-a-service">Remote end publishes a service</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">远端发送 NS 消息到 addr 53</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">rpmsg_recv_done()</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">rpmsg_recv_single()</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">endpoint 53 的 callback</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">rpmsg_ns_cb()</span><br><span class="line">    |</span><br><span class="line">    | RPMSG_NS_CREATE</span><br><span class="line">    v</span><br><span class="line">rpmsg_create_channel()</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">rpmsg_register_device()</span><br><span class="line">    |</span><br><span class="line">    v</span><br><span class="line">匹配上层 rpmsg driver</span><br></pre></td></tr></table></figure><h3 id="RX-buffer-lifecycle">RX buffer lifecycle</h3><p>RX buffer lifecycle:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">probe 时 add_inbuf</span><br><span class="line">    ↓</span><br><span class="line">远端写入消息</span><br><span class="line">    ↓</span><br><span class="line">Linux virtqueue_get_buf</span><br><span class="line">    ↓</span><br><span class="line">调用 callback</span><br><span class="line">    ↓</span><br><span class="line">Linux 重新 add_inbuf</span><br><span class="line">    ↓</span><br><span class="line">远端再次使用</span><br></pre></td></tr></table></figure><p>Therefore, the RX buffer is cyclically reused.</p><h3 id="TX-buffer-lifecycle">TX buffer lifecycle</h3><p>TX buffer lifecycle:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">Linux 从 sbufs 初始池拿 buffer</span><br><span class="line">    ↓</span><br><span class="line">填消息</span><br><span class="line">    ↓</span><br><span class="line">virtqueue_add_outbuf</span><br><span class="line">    ↓</span><br><span class="line">远端消费</span><br><span class="line">    ↓</span><br><span class="line">buffer 进入 used ring</span><br><span class="line">    ↓</span><br><span class="line">Linux virtqueue_get_buf 回收</span><br><span class="line">    ↓</span><br><span class="line">再次发送</span><br></pre></td></tr></table></figure><h2 id="Reference-documentation">Reference documentation</h2><div class="reference-source"><span class="hidden-anchor" id="referfrom_[1]"></span><a class="reference-anchor" href="#referto_[1]">[1]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="AMPRelated：3 Linux rpmsgSubsystem(STM32MP157Solution) " href="https://www.cnblogs.com/arnoldlu/p/18288335">AMPRelated：3 Linux rpmsgSubsystem(STM32MP157Solution) </a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[2]"></span><a class="reference-anchor" href="#referto_[2]">[2]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Multi-core heterogeneous inter-core communication–ipcc" href="https://doc.embedfire.com/linux/stm32mp1/driver/zh/latest/linux_driver/framework_ipcc.html">Multi-core heterogeneous inter-core communication–ipcc</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[3]"></span><a class="reference-anchor" href="#referto_[3]">[3]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Remote Processor Messaging (RPMsg)" href="https://github.com/polarfire-soc/polarfire-soc-documentation/blob/master/applications-and-demos/asymmetric-multiprocessing/rpmsg.md">Remote Processor Messaging (RPMsg)</a></div>]]></content>
    
    
    <summary type="html">This article introduces the implementation principles and core data structures of the virtio-based rpmsg bus driver in the Linux kernel. It discusses the basic communication model of rpmsg and provides a detailed analysis of the rpmsg_device、rpmsg_endpoint creation and destruction logic, as well as the underlying transport mechanisms such as virtqueue send/receive channels, buffer management, DMA mapping, and concurrency control within the virtproc_info private state.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>Commonly Used Data Structures in the Linux Kernel</title>
    <link href="https://even629.com/en/posts/202605243/"/>
    <id>https://even629.com/en/posts/202605243/</id>
    <published>2026-05-24T15:08:13.000Z</published>
    <updated>2026-05-25T15:08:13.000Z</updated>
    
    <content type="html"><![CDATA[<details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-05-24</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the core data structures with high practical usage frequency in the Linux 6.x kernel, detailing the definitions, core APIs, and typical use cases of structures such as doubly linked circular lists, hash linked lists, red-black trees, radix trees, extensible arrays, and priority linked lists.</blockquote><hr><h2 id="Overview">Overview</h2><p>A large number of general-purpose data structures are defined in the Linux kernel, which run through various subsystems such as process scheduling, memory management, file systems, and device drivers. This article follows the<strong>actual usage frequency</strong>from high to low to sort out these data structures, covering data structure definitions, core APIs, and typical use cases.</p><div class="note flat"><div class="note-title">info</div><p>This article is based on the <strong>Linux 6.x</strong> kernel, and some APIs may vary slightly between different versions.</p></div><h2 id="Basic-Containers">Basic Containers</h2><h3 id="list-head-—-Doubly-Linked-Circular-List">list_head — Doubly Linked Circular List</h3><p><strong>Usage frequency: Highest.</strong> This is the most widely used data structure in the Linux kernel, bar none. Almost every subsystem uses it.</p><div class="note flat"><div class="note-title">success</div><p>The Linux linked list implementation will<strong>Separation of data and linked list nodes</strong>, the linked list node is embedded into the structure, rather than the structure containing a linked list pointer. The essence of this design is: a set of linked list operations applies to all data types.</p></div><p><strong>Header file:</strong> <code>&lt;linux/list.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> *<span class="title">next</span>, *<span class="title">prev</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>LIST_HEAD(name)</code></td><td>Statically define and initialize a linked list head</td></tr><tr><td><code>INIT_LIST_HEAD(ptr)</code></td><td>Dynamically initialize a linked list head</td></tr><tr><td><code>list_add(new, head)</code></td><td>Insert after head</td></tr><tr><td><code>list_add_tail(new, head)</code></td><td>Insert before head (tail)</td></tr><tr><td><code>list_del(entry)</code></td><td>Delete node</td></tr><tr><td><code>list_del_init(entry)</code></td><td>Delete and reinitialize node</td></tr><tr><td><code>list_empty(head)</code></td><td>Determine if the linked list is empty</td></tr><tr><td><code>list_entry(ptr, type, member)</code></td><td>Get the structure containing the list_head pointer</td></tr><tr><td><code>list_for_each(pos, head)</code></td><td>Traverse the linked list</td></tr><tr><td><code>list_for_each_entry(pos, head, member)</code></td><td>Traverse the list and get the host structure</td></tr><tr><td><code>list_for_each_entry_safe(pos, n, head, member)</code></td><td>Safe traversal (can delete during traversal)</td></tr><tr><td><code>list_move(list, head)</code></td><td>Move node to a new list</td></tr><tr><td><code>list_splice(list, head)</code></td><td>Merge two lists</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/list.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CNT 10</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> &#123;</span></span><br><span class="line">        <span class="type">int</span> val;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">list</span>;</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Define the list head</span></span><br><span class="line">LIST_HEAD(my_list);</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">list_test_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> i, ret = <span class="number">0</span>;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">entry</span>, *<span class="title">tmp</span>;</span></span><br><span class="line"></span><br><span class="line">        pr_info(<span class="string">&quot;%s is called\n&quot;</span>, __func__);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; CNT; i++) &#123;</span><br><span class="line">                entry = kzalloc(<span class="keyword">sizeof</span>(*entry), GFP_KERNEL);</span><br><span class="line">                <span class="keyword">if</span> (!entry) &#123;</span><br><span class="line">                        ret = -ENOMEM;</span><br><span class="line">                        <span class="keyword">goto</span> cleanup;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                entry-&gt;val = i * <span class="number">2</span>;</span><br><span class="line">                INIT_LIST_HEAD(&amp;entry-&gt;<span class="built_in">list</span>); <span class="comment">// Initialize the list node</span></span><br><span class="line">                list_add_tail(&amp;entry-&gt;<span class="built_in">list</span>, &amp;my_list); <span class="comment">// Add the list to the tail</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        list_for_each_entry(entry, &amp;my_list, <span class="built_in">list</span>)</span><br><span class="line">        &#123;</span><br><span class="line">                pr_info(<span class="string">&quot;val is %d\n&quot;</span>, entry-&gt;val);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">cleanup:</span><br><span class="line">        list_for_each_entry_safe(entry, tmp, &amp;my_list, <span class="built_in">list</span>)</span><br><span class="line">        &#123;</span><br><span class="line">                list_del(&amp;entry-&gt;<span class="built_in">list</span>);</span><br><span class="line">                kfree(entry);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> __exit <span class="title function_">list_test_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">entry</span>, *<span class="title">tmp</span>;</span></span><br><span class="line"></span><br><span class="line">        list_for_each_entry_safe(entry, tmp, &amp;my_list, <span class="built_in">list</span>)</span><br><span class="line">        &#123;</span><br><span class="line">                pr_info(<span class="string">&quot;del %d\n&quot;</span>, entry-&gt;val);</span><br><span class="line">                list_del(&amp;entry-&gt;<span class="built_in">list</span>);</span><br><span class="line">                kfree(entry);</span><br><span class="line">        &#125;</span><br><span class="line">        pr_info(<span class="string">&quot;%s is called\n&quot;</span>, __func__);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(list_test_init);</span><br><span class="line">module_exit(list_test_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;zhaohang&quot;</span>);</span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;A test sample for linux link list&quot;</span>);</span><br></pre></td></tr></table></figure><p>Run</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">~ <span class="comment"># insmod list_test.ko</span></span><br><span class="line">[   11.039661] list_test: loading out-of-tree module taints kernel.</span><br><span class="line">[   11.050065] list_test_init is called</span><br><span class="line">[   11.050235] val is 0</span><br><span class="line">[   11.050289] val is 2</span><br><span class="line">[   11.050325] val is 4</span><br><span class="line">[   11.050390] val is 6</span><br><span class="line">[   11.050429] val is 8</span><br><span class="line">[   11.050466] val is 10</span><br><span class="line">[   11.050734] val is 12</span><br><span class="line">[   11.050808] val is 14</span><br><span class="line">[   11.050885] val is 16</span><br><span class="line">[   11.050936] val is 18</span><br><span class="line">~ <span class="comment"># rmmod list_test.ko</span></span><br><span class="line">[   17.474727] del 0</span><br><span class="line">[   17.474865] del 2</span><br><span class="line">[   17.474913] del 4</span><br><span class="line">[   17.474950] del 6</span><br><span class="line">[   17.474981] del 8</span><br><span class="line">[   17.475060] del 10</span><br><span class="line">[   17.475103] del 12</span><br><span class="line">[   17.475135] del 14</span><br><span class="line">[   17.475169] del 16</span><br><span class="line">[   17.475221] del 18</span><br><span class="line">[   17.475263] list_test_exit is called</span><br></pre></td></tr></table></figure><hr><p><code>list_add</code> and <code>list_add_tail</code>:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * list_add - add a new entry</span></span><br><span class="line"><span class="comment"> * @new: new entry to be added</span></span><br><span class="line"><span class="comment"> * @head: list head to add it after</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Insert a new entry after the specified head.</span></span><br><span class="line"><span class="comment"> * This is good for implementing stacks.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">list_add</span><span class="params">(<span class="keyword">struct</span> list_head *new, <span class="keyword">struct</span> list_head *head)</span></span><br><span class="line">&#123;</span><br><span class="line">__list_add(new, head, head-&gt;next);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * list_add_tail - add a new entry</span></span><br><span class="line"><span class="comment"> * @new: new entry to be added</span></span><br><span class="line"><span class="comment"> * @head: list head to add it before</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Insert a new entry before the specified head.</span></span><br><span class="line"><span class="comment"> * This is useful for implementing queues.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">list_add_tail</span><span class="params">(<span class="keyword">struct</span> list_head *new, <span class="keyword">struct</span> list_head *head)</span></span><br><span class="line">&#123;</span><br><span class="line">__list_add(new, head-&gt;prev, head);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>list_add_tail</code>is inserted into<code>head-&gt;prev</code>and<code>head</code>between. But because this is a ring, “in front of head” is logically equivalent to “the end of the list”.</p><hr><p><code>list_del</code> and <code>list_del_init</code> function</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * list_del - deletes entry from list.</span></span><br><span class="line"><span class="comment"> * @entry: the element to delete from the list.</span></span><br><span class="line"><span class="comment"> * Note: list_empty() on entry does not return true after this, the entry is</span></span><br><span class="line"><span class="comment"> * in an undefined state.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">list_del</span><span class="params">(<span class="keyword">struct</span> list_head *entry)</span></span><br><span class="line">&#123;</span><br><span class="line">__list_del_entry(entry);</span><br><span class="line">entry-&gt;next = LIST_POISON1;</span><br><span class="line">entry-&gt;prev = LIST_POISON2;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * list_del_init - deletes entry from list and reinitialize it.</span></span><br><span class="line"><span class="comment"> * @entry: the element to delete from the list.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">list_del_init</span><span class="params">(<span class="keyword">struct</span> list_head *entry)</span></span><br><span class="line">&#123;</span><br><span class="line">__list_del_entry(entry);</span><br><span class="line">INIT_LIST_HEAD(entry);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><hr><p><code>list_replace</code> Can replace a linked list node</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * list_replace - replace old entry by new one</span></span><br><span class="line"><span class="comment"> * @old : the element to be replaced</span></span><br><span class="line"><span class="comment"> * @new : the new element to insert</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If @old was empty, it will be overwritten.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">list_replace</span><span class="params">(<span class="keyword">struct</span> list_head *old,</span></span><br><span class="line"><span class="params"><span class="keyword">struct</span> list_head *new)</span></span><br><span class="line">&#123;</span><br><span class="line">new-&gt;next = old-&gt;next;</span><br><span class="line">new-&gt;next-&gt;prev = new;</span><br><span class="line">new-&gt;prev = old-&gt;prev;</span><br><span class="line">new-&gt;prev-&gt;next = new;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * list_replace_init - replace old entry by new one and initialize the old one</span></span><br><span class="line"><span class="comment"> * @old : the element to be replaced</span></span><br><span class="line"><span class="comment"> * @new : the new element to insert</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * If @old was empty, it will be overwritten.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">list_replace_init</span><span class="params">(<span class="keyword">struct</span> list_head *old,</span></span><br><span class="line"><span class="params">     <span class="keyword">struct</span> list_head *new)</span></span><br><span class="line">&#123;</span><br><span class="line">list_replace(old, new);</span><br><span class="line">INIT_LIST_HEAD(old);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><h3 id="hlist-—-hash-linked-list">hlist — hash linked list</h3><p><code>hlist</code> is specifically designed for<strong>hash table</strong>designed as a variant of a doubly linked list. That is, when hashing the data to be stored, if a collision occurs, it uses<strong>the linked list approach</strong>to string together and store the conflicting data. Typically, the usage order of elements in a hash table is: data storage —&gt; data retrieval —&gt; data deletion. Compared with <code>list_head</code> the difference lies in: the head node only uses one <code>struct hlist_head</code>(single pointer), saving memory in the hash table array.</p><blockquote><p>Its core design motivation is to solve the standard doubly circular linked list <code>list_head</code> existing when used as a hash bucket<strong>memory waste</strong>and<strong>semantic mismatch</strong>problems.</p></blockquote><div class="table-wrap"><table><thead><tr><th>Feature</th><th><code>list_head</code> (Standard Linked List)</th><th><code>hlist_head</code> + <code>hlist_node</code> (Hash Linked List)</th></tr></thead><tbody><tr><td>Head Node Structure</td><td>Complete Bidirectional Pointer (<code>next</code>, <code>prev</code>)</td><td>Only One Unidirectional Pointer (<code>first</code>)</td></tr><tr><td>Data Node Structure</td><td>Bidirectional Pointer (<code>next</code>, <code>prev</code>)</td><td>Bidirectional Pointer (<code>next</code>, <code>pprev</code>)</td></tr><tr><td>Is Circular?</td><td>Yes (Head and Tail Connected)</td><td>No (Ends with NULL)</td></tr><tr><td>Empty List Check</td><td><code>head-&gt;next == head</code></td><td><code>head-&gt;first == NULL</code></td></tr><tr><td>Memory Overhead (Head Node)</td><td>2 Pointers (16 Bytes/64-bit)</td><td>1 pointer (8 bytes/64 bits)</td></tr></tbody></table></div><p><strong>Header file:</strong> <code>&lt;linux/list.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hlist_head</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">hlist_node</span> *<span class="title">first</span>;</span>  <span class="comment">// Only one pointer!</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hlist_node</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">hlist_node</span> *<span class="title">next</span>, **<span class="title">pprev</span>;</span>  <span class="comment">// pprev points to the next pointer of the previous node</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><blockquote><p><code>pprev</code> Its type is <code>struct hlist_node **</code>(pointer to a pointer).<br>It does not store “the address of the previous node”, but <strong>“the memory address of the next field in the previous node”</strong>。</p><p>For the hlist linked list head -&gt; A -&gt; B</p><ul><li>For node B in the middle of the linked list:<code>B-&gt;pprev == &amp;(A-&gt;next)</code></li><li>For node A of the linked list:<code>A-&gt;pprev == &amp;(head-&gt;first)</code></li></ul></blockquote><p>This design facilitates deletion</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> __hlist_del(<span class="keyword">struct</span> hlist_node *n)</span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hlist_node</span> *<span class="title">next</span> =</span> n-&gt;next;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hlist_node</span> **<span class="title">pprev</span> =</span> n-&gt;pprev;</span><br><span class="line"></span><br><span class="line">WRITE_ONCE(*pprev, next);</span><br><span class="line"><span class="keyword">if</span> (next)</span><br><span class="line">WRITE_ONCE(next-&gt;pprev, pprev);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * hlist_del - Delete the specified hlist_node from its list</span></span><br><span class="line"><span class="comment"> * @n: Node to delete.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note that this function leaves the node in hashed state.  Use</span></span><br><span class="line"><span class="comment"> * hlist_del_init() or similar instead to unhash @n.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">hlist_del</span><span class="params">(<span class="keyword">struct</span> hlist_node *n)</span></span><br><span class="line">&#123;</span><br><span class="line">__hlist_del(n);</span><br><span class="line">n-&gt;next = LIST_POISON1;</span><br><span class="line">n-&gt;pprev = LIST_POISON2;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * hlist_del_init - Delete the specified hlist_node from its list and initialize</span></span><br><span class="line"><span class="comment"> * @n: Node to delete.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note that this function leaves the node in unhashed state.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">hlist_del_init</span><span class="params">(<span class="keyword">struct</span> hlist_node *n)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span> (!hlist_unhashed(n)) &#123;</span><br><span class="line">__hlist_del(n);</span><br><span class="line">INIT_HLIST_NODE(n);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>add related</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * hlist_add_head - add a new entry at the beginning of the hlist</span></span><br><span class="line"><span class="comment"> * @n: new entry to be added</span></span><br><span class="line"><span class="comment"> * @h: hlist head to add it after</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Insert a new entry after the specified head.</span></span><br><span class="line"><span class="comment"> * This is good for implementing stacks.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">hlist_add_head</span><span class="params">(<span class="keyword">struct</span> hlist_node *n, <span class="keyword">struct</span> hlist_head *h)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hlist_node</span> *<span class="title">first</span> =</span> h-&gt;first;</span><br><span class="line">WRITE_ONCE(n-&gt;next, first);</span><br><span class="line"><span class="keyword">if</span> (first)</span><br><span class="line">WRITE_ONCE(first-&gt;pprev, &amp;n-&gt;next);</span><br><span class="line">WRITE_ONCE(h-&gt;first, n);</span><br><span class="line">WRITE_ONCE(n-&gt;pprev, &amp;h-&gt;first);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * hlist_add_before - add a new entry before the one specified</span></span><br><span class="line"><span class="comment"> * @n: new entry to be added</span></span><br><span class="line"><span class="comment"> * @next: hlist node to add it before, which must be non-NULL</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">hlist_add_before</span><span class="params">(<span class="keyword">struct</span> hlist_node *n,</span></span><br><span class="line"><span class="params">    <span class="keyword">struct</span> hlist_node *next)</span></span><br><span class="line">&#123;</span><br><span class="line">WRITE_ONCE(n-&gt;pprev, next-&gt;pprev);</span><br><span class="line">WRITE_ONCE(n-&gt;next, next);</span><br><span class="line">WRITE_ONCE(next-&gt;pprev, &amp;n-&gt;next);</span><br><span class="line">WRITE_ONCE(*(n-&gt;pprev), n);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * hlist_add_behing - add a new entry after the one specified</span></span><br><span class="line"><span class="comment"> * @n: new entry to be added</span></span><br><span class="line"><span class="comment"> * @prev: hlist node to add it after, which must be non-NULL</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">hlist_add_behind</span><span class="params">(<span class="keyword">struct</span> hlist_node *n,</span></span><br><span class="line"><span class="params">    <span class="keyword">struct</span> hlist_node *prev)</span></span><br><span class="line">&#123;</span><br><span class="line">WRITE_ONCE(n-&gt;next, prev-&gt;next);</span><br><span class="line">WRITE_ONCE(prev-&gt;next, n);</span><br><span class="line">WRITE_ONCE(n-&gt;pprev, &amp;prev-&gt;next);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (n-&gt;next)</span><br><span class="line">WRITE_ONCE(n-&gt;next-&gt;pprev, &amp;n-&gt;next);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * hlist_add_fake - create a fake hlist consisting of a single headless node</span></span><br><span class="line"><span class="comment"> * @n: Node to make a fake list out of</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * This makes @n appear to be its own predecessor on a headless hlist.</span></span><br><span class="line"><span class="comment"> * The point of this is to allow things like hlist_del() to work correctly</span></span><br><span class="line"><span class="comment"> * in cases where there is no list.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">void</span> <span class="title function_">hlist_add_fake</span><span class="params">(<span class="keyword">struct</span> hlist_node *n)</span></span><br><span class="line">&#123;</span><br><span class="line">n-&gt;pprev = &amp;n-&gt;next;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * hlist_fake: Is this node a fake hlist?</span></span><br><span class="line"><span class="comment"> * @h: Node to check for being a self-referential fake hlist.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">inline</span> <span class="type">bool</span> <span class="title function_">hlist_fake</span><span class="params">(<span class="keyword">struct</span> hlist_node *h)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">return</span> h-&gt;pprev == &amp;h-&gt;next;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><hr><h3 id="rbtree-—-Red-Black-Tree">rbtree — Red-Black Tree</h3><p>Most used in the kernel<strong>Self-balancing binary search tree</strong>, providing O(log n) search, insertion, and deletion. Each node of a red-black tree has a storage bit indicating the node’s color, which can be Red or Black. Properties of a red-black tree:</p><ul><li>Each node is either black or red.</li><li>The root node is black.</li><li>Every leaf node (NIL) is black. [Note: Here, leaf nodes refer to empty (NIL or NULL) leaf nodes!]</li><li>If a node is red, then its children must be black.</li><li>All paths from a node to its descendant nodes contain the same number of black nodes. This property ensures that no path is more than twice as long as any other, thus, a red-black tree is a relatively balanced binary tree.</li></ul><p>All operations on a red-black tree must maintain its properties. Red-black trees are widely used, mainly to store ordered data, with a time complexity of O(log n) and very high efficiency. cfs_rq uses a red-black tree to store tasks.</p><p><strong>Header file:</strong> <code>&lt;linux/rbtree.h&gt;</code> / <code>&lt;linux/rbtree_augmented.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> &#123;</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span>  __rb_parent_color;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">rb_right</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">rb_left</span>;</span></span><br><span class="line">&#125; __attribute__((aligned(<span class="keyword">sizeof</span>(<span class="type">long</span>))));</span><br><span class="line">    <span class="comment">/* The alignment might seem pointless, but allegedly CRIS needs it */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rb_root</span> &#123;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">rb_node</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><blockquote><p>At first glance, it seems there is no field defined for color here, but this is where the cleverness of this red-black tree implementation lies.<code>__rb_parent_color</code>This field actually contains both color information and a pointer to the parent node. Because this field is of type long and requires alignment of size sizeof(long), on a typical 32-bit machine, the last two bits are always 0, so one of these bits can be used to represent the color.</p><p>The key lies in <strong>Memory alignment (Alignment)</strong>：</p><ul><li><code>struct rb_node</code> forced to align by <code>sizeof(long)</code> alignment.</li><li>On a 32-bit system,<code>sizeof(long) == 4</code>, meaning any valid <code>rb_node</code> pointer address must be <strong>a multiple of 4</strong>, i.e., the lowest binary <strong>2 bits</strong> are always <code>00</code>。</li><li>On a 64-bit system,<code>sizeof(long) == 8</code>, the lowest <strong>3 bits</strong> are always <code>000</code>。</li></ul><p>In fact, the least significant bit is used here to represent color information. The following operations on the parent pointer and color information are essentially operations on<code>rb_parent_color</code>’s bits.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> rb_parent(r)   ((struct rb_node *)((r)-&gt;__rb_parent_color &amp; ~3))</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RB_ROOT(struct rb_root) &#123; NULL, &#125;</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span>rb_entry(ptr, type, member) container_of(ptr, type, member)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RB_EMPTY_ROOT(root)  (READ_ONCE((root)-&gt;rb_node) == NULL)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* &#x27;empty&#x27; nodes are nodes that are known not to be inserted in an rbtree */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RB_EMPTY_NODE(node)  \</span></span><br><span class="line"><span class="meta">((node)-&gt;__rb_parent_color == (unsigned long)(node))</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RB_CLEAR_NODE(node)  \</span></span><br><span class="line"><span class="meta">((node)-&gt;__rb_parent_color = (unsigned long)(node))</span></span><br></pre></td></tr></table></figure></blockquote><p>Linux’s red-black tree implementation is optimized for speed, so it has one less level of indirection than traditional implementations (with better cache locality). Each <code>struct rb_node</code> instance of the structure is embedded in the data structure it manages, so there is no need to rely on pointers to separate <code>rb_node</code> from the data structure it manages.</p><ul><li><p><strong>Users should write their own tree search and insertion functions to call the provided red-black tree functions, rather than using a comparison callback function pointer.</strong></p></li><li><p><strong>Locking code is also left to the user of the red-black tree to write</strong>。</p></li></ul><p><strong>Example</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// SPDX-License-Identifier: GPL-2.0</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * rbtree_demo.c - Linux 5.10.x Red-Black Tree Module Demo</span></span><br><span class="line"><span class="comment"> * Demonstration: Insert、Search、Delete、In-order traversal、Reverse-order traversal、Get first and last nodes</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/init.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/rbtree.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/random.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== 1. Define a custom structure containing rb_node ========== */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> &#123;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> <span class="title">rb</span>;</span> <span class="comment">/* Must be embedded as a member, usually at the beginning or anywhere */</span></span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span> data; <span class="comment">/* Data */</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Global red-black tree root node */</span></span><br><span class="line"><span class="type">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">rb_root</span> <span class="title">my_tree</span> =</span> RB_ROOT;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== 2. Auxiliary macro: Reverse lookup of host structure from rb_node ========== */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> rb_entry_my(ptr) rb_entry((ptr), struct my_node, rb)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== 3. Core operation encapsulation ========== */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Find node - O(log n)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> my_node *<span class="title function_">my_rb_search</span><span class="params">(<span class="keyword">struct</span> rb_root *root, <span class="type">unsigned</span> <span class="type">long</span> data)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">node</span> =</span> root-&gt;rb_node;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (node) &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">entry</span> =</span> rb_entry_my(node);</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (data &lt; entry-&gt;data) <span class="comment">// Current node is greater than the key to find, go to the left subtree</span></span><br><span class="line">                        node = node-&gt;rb_left;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> (data &gt; entry-&gt;data) <span class="comment">// Current node is less than the key to find, go to the right</span></span><br><span class="line">                        node = node-&gt;rb_right;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                        <span class="keyword">return</span> entry; <span class="comment">/* Found */</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>; <span class="comment">/* Not found */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Insert node - O(log n)</span></span><br><span class="line"><span class="comment"> * Return: true=Newly inserted, false=keyAlready exists(Not inserted)</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 【Key】Linux 5.10.x Use a two-step method:</span></span><br><span class="line"><span class="comment"> *   1) rb_link_node()  : Link the node under the parent node（Do not color）</span></span><br><span class="line"><span class="comment"> *   2) rb_insert_color(): Fix red-black tree properties（Rotate+Recolor）</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">bool</span> <span class="title function_">my_rb_insert</span><span class="params">(<span class="keyword">struct</span> rb_root *root, <span class="keyword">struct</span> my_node *new_node)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> **<span class="title">link</span> =</span> &amp;root-&gt;rb_node; <span class="comment">// Insertion position to be found</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">parent</span> =</span> <span class="literal">NULL</span>;</span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span> data = new_node-&gt;data;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Step 1: Standard BST search for insertion position */</span></span><br><span class="line">        <span class="keyword">while</span> (*link) &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">entry</span> =</span> rb_entry_my(*link);</span><br><span class="line">                parent = *link;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (data &lt; entry-&gt;data)</span><br><span class="line">                        link = &amp;(*link)-&gt;rb_left;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> (data &gt; entry-&gt;data)</span><br><span class="line">                        link = &amp;(*link)-&gt;rb_right;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">false</span>; <span class="comment">/* Key already exists, do not insert duplicate */</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Step 2: Link and color */</span></span><br><span class="line">        rb_link_node(&amp;new_node-&gt;rb, parent, link);</span><br><span class="line">        rb_insert_color(&amp;new_node-&gt;rb, root);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Delete node - O(log n)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">my_rb_erase</span><span class="params">(<span class="keyword">struct</span> rb_root *root, <span class="keyword">struct</span> my_node *node)</span></span><br><span class="line">&#123;</span><br><span class="line">        rb_erase(&amp;node-&gt;rb, root);</span><br><span class="line">        kfree(node);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Destroy the entire tree</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">my_rb_destroy</span><span class="params">(<span class="keyword">struct</span> rb_root *root)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">node</span>;</span></span><br><span class="line">        <span class="comment">/* Safely release in postorder to avoid accessing freed child nodes */</span></span><br><span class="line">        <span class="keyword">while</span> ((node = rb_first_postorder(root))) &#123;</span><br><span class="line">                rb_erase(node, root);</span><br><span class="line">                kfree(rb_entry_my(node));</span><br><span class="line">        &#125;</span><br><span class="line">        *root = RB_ROOT;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== 4. Module Initialization: Batch Insertion + Verification ========== */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">rbtree_demo_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">int</span> i;</span><br><span class="line">        <span class="type">unsigned</span> <span class="type">long</span> keys[] = &#123; <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span> &#125;;</span><br><span class="line">        <span class="type">int</span> count = ARRAY_SIZE(keys);</span><br><span class="line"></span><br><span class="line">        pr_info(<span class="string">&quot;rbtree_demo: === Module Loaded ===\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* --- Insertion Test --- */</span></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; count; i++) &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">node</span> =</span> kzalloc(<span class="keyword">sizeof</span>(*node), GFP_KERNEL);</span><br><span class="line">                <span class="keyword">if</span> (!node)</span><br><span class="line">                        <span class="keyword">return</span> -ENOMEM;</span><br><span class="line"></span><br><span class="line">                node-&gt;data = keys[i];</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (my_rb_insert(&amp;my_tree, node))</span><br><span class="line">                        pr_info(<span class="string">&quot;rbtree_demo: INSERT data=%lu OK\n&quot;</span>, keys[i]);</span><br><span class="line">                <span class="keyword">else</span> &#123;</span><br><span class="line">                        pr_warn(<span class="string">&quot;rbtree_demo: INSERT data=%lu DUPLICATE\n&quot;</span>, keys[i]);</span><br><span class="line">                        kfree(node);</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* --- Search Test --- */</span></span><br><span class="line">        &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">found</span> =</span> my_rb_search(&amp;my_tree, <span class="number">4</span>);</span><br><span class="line">                <span class="keyword">if</span> (found)</span><br><span class="line">                        pr_info(<span class="string">&quot;rbtree_demo: SEARCH data=4 =&gt; %lu\n&quot;</span>, found-&gt;data);</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                        pr_warn(<span class="string">&quot;rbtree_demo: SEARCH data=4 =&gt; Not Found\n&quot;</span>);</span><br><span class="line">                </span><br><span class="line"></span><br><span class="line">                found = my_rb_search(&amp;my_tree, <span class="number">666</span>);</span><br><span class="line">                <span class="keyword">if</span> (found)</span><br><span class="line">                        pr_info(<span class="string">&quot;rbtree_demo: SEARCH data=99 =&gt; %lu\n&quot;</span>, found-&gt;data);</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                        pr_warn(<span class="string">&quot;rbtree_demo: SEARCH data=99 =&gt; Not Found\n&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* --- In-order Traversal --- */</span></span><br><span class="line">        pr_info(<span class="string">&quot;rbtree_demo: IN-ORDER TRAVERSAL:\n&quot;</span>);</span><br><span class="line">        &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">node</span>;</span></span><br><span class="line">                <span class="keyword">for</span> (node = rb_first(&amp;my_tree); node; node = rb_next(node)) &#123;</span><br><span class="line">                        <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">entry</span> =</span> rb_entry_my(node);</span><br><span class="line">                        pr_info(<span class="string">&quot;       data=%lu\n&quot;</span>, entry-&gt;data);</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* --- Reverse Traversal --- */</span></span><br><span class="line">        pr_info(<span class="string">&quot;rbtree_demo: REVERSE TRAVERSAL:\n&quot;</span>);</span><br><span class="line">        &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">node</span>;</span></span><br><span class="line">                <span class="keyword">for</span> (node = rb_last(&amp;my_tree); node; node = rb_prev(node)) &#123;</span><br><span class="line">                        <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">entry</span> =</span> rb_entry_my(node);</span><br><span class="line">                        pr_info(<span class="string">&quot;       data=%lu\n&quot;</span>, entry-&gt;data);</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* --- Get Min/Max Node --- */</span></span><br><span class="line">        &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">min</span> =</span> rb_entry_my(rb_first(&amp;my_tree));</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">max</span> =</span> rb_entry_my(rb_last(&amp;my_tree));</span><br><span class="line">                pr_info(<span class="string">&quot;rbtree_demo: MIN=%lu MAX=%lu\n&quot;</span>, min-&gt;data, max-&gt;data);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* --- Delete Test --- */</span></span><br><span class="line">        &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">to_del</span> =</span> my_rb_search(&amp;my_tree, <span class="number">4</span>);</span><br><span class="line">                <span class="keyword">if</span> (to_del) &#123;</span><br><span class="line">                        pr_info(<span class="string">&quot;rbtree_demo: ERASE data=4\n&quot;</span>);</span><br><span class="line">                        my_rb_erase(&amp;my_tree, to_del);</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* In-order traversal again to confirm deletion result */</span></span><br><span class="line">        pr_info(<span class="string">&quot;rbtree_demo: AFTER ERASE 30:\n&quot;</span>);</span><br><span class="line">        &#123;</span><br><span class="line">                <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> *<span class="title">node</span>;</span></span><br><span class="line">                <span class="keyword">for</span> (node = rb_first(&amp;my_tree); node; node = rb_next(node)) &#123;</span><br><span class="line">                        <span class="class"><span class="keyword">struct</span> <span class="title">my_node</span> *<span class="title">entry</span> =</span> rb_entry_my(node);</span><br><span class="line">                        pr_info(<span class="string">&quot;data=%lu\n&quot;</span>, entry-&gt;data);</span><br><span class="line">                &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== 5. Module Unload: Clean Up All Resources ========== */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> __exit <span class="title function_">rbtree_demo_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">        my_rb_destroy(&amp;my_tree);</span><br><span class="line">        pr_info(<span class="string">&quot;rbtree_demo: === Module Unloaded ===\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(rbtree_demo_init);</span><br><span class="line">module_exit(rbtree_demo_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;even629&quot;</span>);</span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;Linux 5.10.x rbtree operations demo&quot;</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure><hr><h3 id="radix-tree-—-Radix-Tree">radix_tree — Radix Tree</h3><p><code>xarray</code> predecessor, used for mapping integer IDs to pointers. Although <code>xarray</code> has gradually replaced it, there is still a large amount of code using radix trees in the kernel.</p><p>If it is a new project, please use directly <code>&lt;linux/xarray.h&gt;</code> the XArray API. XArray fixes many design flaws of radix_tree (such as preload complexity, index offset issues), and the API is more concise. radix_tree in 5.10.x is just a compatibility layer on top of XArray.</p><p><strong>Header file:</strong> <code>&lt;linux/radix-tree.h&gt;</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> radix_tree_rootxarray</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> radix_tree_nodexa_node</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">radix_tree_preload</span> &#123;</span></span><br><span class="line"><span class="type">local_lock_t</span> lock;</span><br><span class="line"><span class="type">unsigned</span> nr;</span><br><span class="line"><span class="comment">/* nodes-&gt;parent points to next preallocated node */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">radix_tree_node</span> *<span class="title">nodes</span>;</span></span><br><span class="line">&#125;;</span><br><span class="line">DECLARE_PER_CPU(<span class="keyword">struct</span> radix_tree_preload, radix_tree_preloads);</span><br></pre></td></tr></table></figure><p>visible<code>linux-5.10.x</code>It has been replaced by xarray in</p><p>Example</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// SPDX-License-Identifier: GPL-2.0</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * radix_tree_demo.c - Linux 5.10.x Radix Tree Module Demo (Fixed)</span></span><br><span class="line"><span class="comment"> * Demo: Initialization、Preloading、Insert、Find、Delete、Tag(tag)Operation、Safe destruction</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/module.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/kernel.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/init.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/radix-tree.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/slab.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/spinlock.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;linux/rcupdate.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* Custom storage data structure */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> &#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> id;</span><br><span class="line">    <span class="type">char</span> name[<span class="number">32</span>];</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Global radix tree and protection lock */</span></span><br><span class="line"><span class="type">static</span> <span class="title function_">RADIX_TREE</span><span class="params">(my_rtree, GFP_ATOMIC)</span>;</span><br><span class="line"><span class="type">static</span> <span class="title function_">DEFINE_SPINLOCK</span><span class="params">(my_rtree_lock)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== Helper Functions ========== */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> my_data *<span class="title function_">create_data</span><span class="params">(<span class="type">unsigned</span> <span class="type">long</span> id, <span class="type">const</span> <span class="type">char</span> *name)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">d</span> =</span> kmalloc(<span class="keyword">sizeof</span>(*d), GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (d) &#123;</span><br><span class="line">        d-&gt;id = id;</span><br><span class="line">        strscpy(d-&gt;name, name, <span class="keyword">sizeof</span>(d-&gt;name));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> d;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== Core Operation Encapsulation ========== */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Safely insert node</span></span><br><span class="line"><span class="comment"> * 【Critical】must first preload then insert within the lock，avoid triggering sleep allocation while holding the lock, which could cause deadlock or OOM</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> <span class="title function_">safe_insert</span><span class="params">(<span class="type">unsigned</span> <span class="type">long</span> index, <span class="keyword">struct</span> my_data *data)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Pre-allocate node memory (sleep allowed) */</span></span><br><span class="line">    ret = radix_tree_preload(GFP_KERNEL);</span><br><span class="line">    <span class="keyword">if</span> (ret)</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line"></span><br><span class="line">    spin_lock(&amp;my_rtree_lock);</span><br><span class="line">    ret = radix_tree_insert(&amp;my_rtree, index, data);</span><br><span class="line">    spin_unlock(&amp;my_rtree_lock);</span><br><span class="line"></span><br><span class="line">    radix_tree_preload_end();</span><br><span class="line">    <span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Find node - RCU Read-side safe</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="keyword">struct</span> my_data *<span class="title function_">safe_lookup</span><span class="params">(<span class="type">unsigned</span> <span class="type">long</span> index)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">data</span>;</span></span><br><span class="line"></span><br><span class="line">    rcu_read_lock();</span><br><span class="line">    data = radix_tree_lookup(&amp;my_rtree, index);</span><br><span class="line">    rcu_read_unlock();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> data;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Delete and free node</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">safe_delete</span><span class="params">(<span class="type">unsigned</span> <span class="type">long</span> index)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">data</span>;</span></span><br><span class="line"></span><br><span class="line">    spin_lock(&amp;my_rtree_lock);</span><br><span class="line">    data = radix_tree_delete(&amp;my_rtree, index);</span><br><span class="line">    spin_unlock(&amp;my_rtree_lock);</span><br><span class="line"></span><br><span class="line">    kfree(data); <span class="comment">/* delete returns the removed pointer, the caller is responsible for freeing it */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Use Tag Batch marking and retrieval</span></span><br><span class="line"><span class="comment"> * Fixed：Use struct radix_tree_iter as an iterator</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">demo_tag_operations</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">d</span>;</span></span><br><span class="line">    <span class="type">void</span> **slot;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">radix_tree_iter</span> <span class="title">iter</span>;</span> <span class="comment">/* correct iterator type */</span></span><br><span class="line"></span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: === TAG Operations ===\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* tag index=100 with tag 0 */</span></span><br><span class="line">    spin_lock(&amp;my_rtree_lock);</span><br><span class="line">    radix_tree_tag_set(&amp;my_rtree, <span class="number">100</span>, <span class="number">0</span>);</span><br><span class="line">    spin_unlock(&amp;my_rtree_lock);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* batch retrieval by tag */</span></span><br><span class="line">    rcu_read_lock();</span><br><span class="line">    radix_tree_for_each_tagged(slot, &amp;my_rtree, &amp;iter, <span class="number">0</span>, <span class="number">0</span>) &#123;</span><br><span class="line">        d = radix_tree_deref_slot(slot);</span><br><span class="line">        <span class="keyword">if</span> (unlikely(radix_tree_deref_retry(d))) &#123;</span><br><span class="line">            slot = radix_tree_iter_retry(&amp;iter); <span class="comment">/* retry passing iter */</span></span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (d)</span><br><span class="line">            pr_info(<span class="string">&quot;rtree_demo: TAGGED index=%lu name=%s\n&quot;</span>,</span><br><span class="line">                    iter.index, d-&gt;name); <span class="comment">/* get index from iter.index */</span></span><br><span class="line">    &#125;</span><br><span class="line">    rcu_read_unlock();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== Module Entry ========== */</span></span><br><span class="line"><span class="type">static</span> <span class="type">int</span> __init <span class="title function_">radix_tree_demo_init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">d</span>;</span></span><br><span class="line">    <span class="type">int</span> ret;</span><br><span class="line"></span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: === Module Loaded ===\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* RADIX_TREE() macro is statically initialized, no manual INIT required_RADIX_TREE */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* --- Insertion Test --- */</span></span><br><span class="line">    d = create_data(<span class="number">42</span>, <span class="string">&quot;hello&quot;</span>);</span><br><span class="line">    ret = safe_insert(<span class="number">42</span>, d);</span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: INSERT index=42 ret=%d\n&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line">    d = create_data(<span class="number">100</span>, <span class="string">&quot;world&quot;</span>);</span><br><span class="line">    ret = safe_insert(<span class="number">100</span>, d);</span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: INSERT index=100 ret=%d\n&quot;</span>, ret);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Test duplicate insertion */</span></span><br><span class="line">    d = create_data(<span class="number">42</span>, <span class="string">&quot;duplicate&quot;</span>);</span><br><span class="line">    ret = safe_insert(<span class="number">42</span>, d);</span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: INSERT DUP index=42 ret=%d (expect -EEXIST)\n&quot;</span>, ret);</span><br><span class="line">    kfree(d); <span class="comment">/* Duplicate insertion failed, manual release */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* --- Search Test --- */</span></span><br><span class="line">    d = safe_lookup(<span class="number">42</span>);</span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: LOOKUP 42 =&gt; %s\n&quot;</span>, d ? d-&gt;name : <span class="string">&quot;NULL&quot;</span>);</span><br><span class="line"></span><br><span class="line">    d = safe_lookup(<span class="number">999</span>);</span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: LOOKUP 999 =&gt; %s\n&quot;</span>, d ? d-&gt;name : <span class="string">&quot;NULL&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* --- Tag Test --- */</span></span><br><span class="line">    demo_tag_operations();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* --- Deletion Test --- */</span></span><br><span class="line">    safe_delete(<span class="number">42</span>);</span><br><span class="line">    d = safe_lookup(<span class="number">42</span>);</span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: AFTER DELETE 42 =&gt; %s\n&quot;</span>, d ? d-&gt;name : <span class="string">&quot;NULL&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ========== Module Unload: Safely traverse and release all remaining nodes ========== */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> __exit <span class="title function_">radix_tree_demo_exit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">d</span>;</span></span><br><span class="line">    <span class="type">void</span> **slot;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">radix_tree_iter</span> <span class="title">iter</span>;</span> <span class="comment">/* Correct iterator type */</span></span><br><span class="line"></span><br><span class="line">    rcu_read_lock();</span><br><span class="line">    radix_tree_for_each_slot(slot, &amp;my_rtree, &amp;iter, <span class="number">0</span>) &#123;</span><br><span class="line">        d = radix_tree_deref_slot(slot);</span><br><span class="line">        <span class="keyword">if</span> (unlikely(radix_tree_deref_retry(d))) &#123;</span><br><span class="line">            slot = radix_tree_iter_retry(&amp;iter); <span class="comment">/* retry passes iter */</span></span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (d) &#123;</span><br><span class="line">            <span class="comment">/* Must be deleted within the lock, and use iter.index */</span></span><br><span class="line">            spin_lock(&amp;my_rtree_lock);</span><br><span class="line">            radix_tree_delete(&amp;my_rtree, iter.index);</span><br><span class="line">            spin_unlock(&amp;my_rtree_lock);</span><br><span class="line">            kfree(d);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    rcu_read_unlock();</span><br><span class="line"></span><br><span class="line">    pr_info(<span class="string">&quot;rtree_demo: === Module Unloaded ===\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(radix_tree_demo_init);</span><br><span class="line">module_exit(radix_tree_demo_exit);</span><br><span class="line"></span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>);</span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;even629&quot;</span>);</span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;Linux 5.10.x radix_tree operations demo (fixed iterator)&quot;</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure><hr><h3 id="xarray-—-Extensible-arrays">xarray — Extensible arrays</h3><p><code>xarray</code> Introduced in Linux 4.20<strong>A new generation radix tree replacement</strong>, providing a mapping from integers (<code>unsigned long</code>) to pointers, with a cleaner API and better performance.</p><p><strong>Header file:</strong> <code>&lt;linux/xarray.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">xarray</span> &#123;</span></span><br><span class="line">    <span class="type">spinlock_t</span>  xa_lock;</span><br><span class="line">    <span class="type">gfp_t</span>       xa_flags;</span><br><span class="line">    <span class="type">void</span> __rcu *xa_head;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>DEFINE_XARRAY(name)</code></td><td>Statically define xarray</td></tr><tr><td><code>xa_init(xa)</code></td><td>Dynamic initialization</td></tr><tr><td><code>xa_store(xa, index, entry, gfp)</code></td><td>Store entry</td></tr><tr><td><code>xa_load(xa, index)</code></td><td>Read entry</td></tr><tr><td><code>xa_erase(xa, index)</code></td><td>Delete entry</td></tr><tr><td><code>xa_insert(xa, index, entry, gfp)</code></td><td>Insert (key must not already exist)</td></tr><tr><td><code>xa_for_each(xa, index, entry)</code></td><td>Traverse all entries</td></tr><tr><td><code>xa_find(xa, indexp, max, filter)</code></td><td>Find entries in range</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">DEFINE_XARRAY(my_xa);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Store</span></span><br><span class="line">xa_store(&amp;my_xa, <span class="number">0</span>, ptr1, GFP_KERNEL);</span><br><span class="line">xa_store(&amp;my_xa, <span class="number">42</span>, ptr2, GFP_KERNEL);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Read</span></span><br><span class="line"><span class="type">void</span> *p = xa_load(&amp;my_xa, <span class="number">42</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Traverse</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">long</span> index;</span><br><span class="line"><span class="type">void</span> *entry;</span><br><span class="line">xa_for_each(&amp;my_xa, index, entry) &#123;</span><br><span class="line">    pr_info(<span class="string">&quot;index=%lu, entry=%p\n&quot;</span>, index, entry);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><h3 id="plist-—-priority-linked-list">plist — priority linked list</h3><p><code>plist</code> On <code>list_head</code> added to<strong>priority</strong>, the head always points to the node with the highest priority (a smaller prio value represents a higher priority), commonly used in scenarios where “the highest priority must always be processed first”.</p><p><strong>Header file:</strong> <code>&lt;linux/plist.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">plist_node</span> &#123;</span></span><br><span class="line">    <span class="type">int</span>             prio;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">prio_list</span>;</span>  <span class="comment">// Link to nodes of the same priority</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">node_list</span>;</span>  <span class="comment">// Overall linked list</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">plist_head</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">node_list</span>;</span>  <span class="comment">// All nodes sorted by priority</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>plist_head_init(head)</code></td><td>Initialization</td></tr><tr><td><code>plist_node_init(node, prio)</code></td><td>Initialize node</td></tr><tr><td><code>plist_add(node, head)</code></td><td>Insert by priority</td></tr><tr><td><code>plist_del(node, head)</code></td><td>Delete node</td></tr><tr><td><code>plist_first(head)</code></td><td>Get the node with the highest priority</td></tr><tr><td><code>plist_head_empty(head)</code></td><td>Check if empty</td></tr></tbody></table></div><hr><h3 id="llist-—-lockless-linked-list">llist — lockless linked list</h3><p><code>llist</code>(lock-less list) is a<strong>lockless singly linked list</strong>, implemented based on CAS operations, performs better than spinlock + in specific scenarios (such as interrupts and process shared data) <code>list_head</code> performs better.</p><p><strong>Header file:</strong> <code>&lt;linux/llist.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">llist_head</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">llist_node</span> *<span class="title">first</span>;</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">llist_node</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">llist_node</span> *<span class="title">next</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>llist_add(new, head)</code></td><td>Insert at head (lock-free)</td></tr><tr><td><code>llist_del_all(head)</code></td><td>Atomically detach the entire linked list</td></tr><tr><td><code>llist_del_first(head)</code></td><td>Delete the first node</td></tr><tr><td><code>llist_empty(head)</code></td><td>Check if empty</td></tr></tbody></table></div><p><strong>Typical pattern:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Producer (can be in interrupt context)</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">llist_node</span> *<span class="title">node</span> =</span> kmalloc(<span class="keyword">sizeof</span>(*node), GFP_ATOMIC);</span><br><span class="line">llist_add(node, &amp;my_llist);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Consumer (process context)</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">llist_node</span> *<span class="title">list</span> =</span> llist_del_all(&amp;my_llist);  <span class="comment">// Atomically take the entire linked list</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">llist_node</span> *<span class="title">entry</span>, *<span class="title">tmp</span>;</span></span><br><span class="line">llist_for_each_entry_safe(entry, tmp, <span class="built_in">list</span>) &#123;</span><br><span class="line">    process(entry);</span><br><span class="line">    kfree(entry);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><h3 id="rhashtable-—-resizable-hash-table">rhashtable — resizable hash table</h3><p><code>rhashtable</code> is a<strong>automatically expandable and shrinkable</strong>hash table implementation that supports RCU lookup, suitable for hash scenarios requiring dynamic growth.</p><p><strong>Header file:</strong> <code>&lt;linux/rhashtable.h&gt;</code></p><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>rhashtable_init(ht, params)</code></td><td>Initialization</td></tr><tr><td><code>rhashtable_insert_slow(ht, key, obj)</code></td><td>Insertion</td></tr><tr><td><code>rhashtable_lookup(ht, key, params)</code></td><td>Lookup</td></tr><tr><td><code>rhashtable_remove(ht, obj, params)</code></td><td>Deletion</td></tr><tr><td><code>rhashtable_free_and_destroy(ht, fn, data)</code></td><td>Destruction</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>Connection tracking table for network namespaces</li><li>XFRM security policy database</li><li>Hash type implementation of BPF map</li></ul><hr><h3 id="maple-tree-—-Maple-Tree">maple_tree — Maple Tree</h3><p>A new data structure introduced in Linux 6.1 to replace the red-black tree + linked list combination in VMA management.<code>maple_tree</code> is a <strong>B-tree variant</strong>, supporting<strong>range operations</strong>(range operations), which is highly efficient for VMA lookup, traversal, and gap searching.</p><p><strong>Header file:</strong> <code>&lt;linux/maple_tree.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">maple_tree</span> &#123;</span></span><br><span class="line">    <span class="type">spinlock_t</span>      ma_lock;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>    ma_flags;</span><br><span class="line">    <span class="type">void</span> __rcu     *ma_root;  <span class="comment">// RCU protection</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>mt_init(mt)</code></td><td>Initialization</td></tr><tr><td><code>mtree_lock(mt)</code></td><td>Acquire write lock</td></tr><tr><td><code>mtree_unlock(mt)</code></td><td>Release write lock</td></tr><tr><td><code>mas_store(mas, entry)</code></td><td>Store entry</td></tr><tr><td><code>mas_find(mas, max)</code></td><td>Lookup</td></tr><tr><td><code>mas_erase(mas)</code></td><td>Delete</td></tr><tr><td><code>MTREE_INIT(mt, flags)</code></td><td>Static initialization</td></tr><tr><td><code>mtree_destroy(mt)</code></td><td>Destroy</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li><strong>VMA management</strong>: Linux 6.1+ uses <code>maple_tree</code> to replace red-black tree + doubly linked list management <code>vm_area_struct</code></li><li>User-space programs (user-space RCU library URCU also implements maple tree)</li></ul><hr><h3 id="interval-tree-—-Interval-tree">interval_tree — Interval tree</h3><p>Interval tree is an enhanced red-black tree, used to manage<strong>intervals</strong>([start, last]), supporting fast lookup of all intervals overlapping with a given interval. Based on <code>rbtree_augmented</code> implementation.</p><p><strong>Header file:</strong> <code>&lt;linux/interval_tree.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">interval_tree_node</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> <span class="title">rb</span>;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> start;     <span class="comment">// Interval start</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> last;      <span class="comment">// Interval end</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> __subtree_last;  <span class="comment">// Maximum last in subtree (augmented info)</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>interval_tree_insert(node, root)</code></td><td>Insert</td></tr><tr><td><code>interval_tree_remove(node, root)</code></td><td>Delete</td></tr><tr><td><code>interval_tree_iter_first(root, start, last)</code></td><td>Find first overlapping interval</td></tr><tr><td><code>interval_tree_iter_next(node, start, last)</code></td><td>Find next overlapping interval</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>VMA interval lookup (find virtual memory areas overlapping with a given address range)</li><li>GEM buffer management in DRM GPU drivers</li></ul><hr><h3 id="klist-—-kernel-object-linked-list">klist — kernel object linked list</h3><p><code>klist</code> is correct <code>list_head</code> wrapper, and <code>kobject</code> Used in conjunction with the system, providing get/put reference counting protection: automatically acquires a reference to node objects while traversing the list, preventing nodes from being freed during traversal.</p><p><strong>Header file:</strong> <code>&lt;linux/klist.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">klist_node</span> &#123;</span></span><br><span class="line">    <span class="type">void</span>            *n_klist;   <span class="comment">// Field no longer used</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">n_node</span>;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kref</span>     <span class="title">n_ref</span>;</span>      <span class="comment">// Reference count</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">klist</span> &#123;</span></span><br><span class="line">    <span class="type">spinlock_t</span>      k_lock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">k_list</span>;</span></span><br><span class="line">    <span class="type">void</span>            (*get)(<span class="keyword">struct</span> klist_node *);</span><br><span class="line">    <span class="type">void</span>            (*put)(<span class="keyword">struct</span> klist_node *);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>klist_add_head(n, k)</code></td><td>Add to head</td></tr><tr><td><code>klist_add_tail(n, k)</code></td><td>Add to tail</td></tr><tr><td><code>klist_del(n)</code></td><td>Delete</td></tr><tr><td><code>klist_iter_init(k, i)</code></td><td>Initialize iterator</td></tr><tr><td><code>klist_next(i)</code></td><td>Get next node (auto get/put)</td></tr><tr><td><code>klist_iter_exit(i)</code></td><td>Cleanup iterator</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>In the device driver model <code>bus_type</code> 's device list</li><li>In the device driver model <code>driver</code> 's device list</li></ul><hr><h2 id="ID-Bitmap-and-DMA">ID, Bitmap, and DMA</h2><h3 id="idr-—-ID-allocator">idr — ID allocator</h3><p><code>idr</code> Provides<strong>integer ID to pointer</strong>mapping, automatically allocating a unique integer ID and associating it to a pointer. Suitable for scenarios where “an integer handle is needed”.</p><p><strong>Header file:</strong> <code>&lt;linux/idr.h&gt;</code></p><p><strong>Core API (modern interface):</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>idr_alloc(idr, ptr, start, end, gfp)</code></td><td>Allocate ID and associate pointer</td></tr><tr><td><code>idr_find(idr, id)</code></td><td>Find pointer by ID</td></tr><tr><td><code>idr_remove(idr, id)</code></td><td>Delete ID mapping</td></tr><tr><td><code>idr_for_each(idr, fn, data)</code></td><td>Iterate over all entries</td></tr><tr><td><code>idr_destroy(idr)</code></td><td>Destroy idr</td></tr><tr><td><code>idr_init(idr)</code></td><td>Initialize</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">DEFINE_IDR(my_idr);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Allocate</span></span><br><span class="line"><span class="type">int</span> id;</span><br><span class="line">id = idr_alloc(&amp;my_idr, ptr, <span class="number">1</span>, <span class="number">0</span>, GFP_KERNEL);  <span class="comment">// Allocate starting from 1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Find</span></span><br><span class="line"><span class="type">void</span> *p = idr_find(&amp;my_idr, id);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Release</span></span><br><span class="line">idr_remove(&amp;my_idr, id);</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>Process PID management</li><li>Device minor number allocation</li><li>GPU DRM driver handle management (GEM buffer handle)</li></ul><hr><h3 id="ida-—-IDA-allocator">ida — IDA allocator</h3><p><code>ida</code> is <code>idr</code> A simplified version that only allocates integer IDs without associating pointers (used when only unique integer IDs are needed, with lower memory overhead).</p><p><strong>Header file:</strong> <code>&lt;linux/idr.h&gt;</code></p><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>ida_alloc(ida, gfp)</code></td><td>Allocate an ID</td></tr><tr><td><code>ida_free(ida, id)</code></td><td>Release ID</td></tr><tr><td><code>ida_alloc_range(ida, min, max, gfp)</code></td><td>Allocate ID in range</td></tr><tr><td><code>ida_init(ida)</code></td><td>Initialize</td></tr><tr><td><code>ida_destroy(ida)</code></td><td>Destroy</td></tr></tbody></table></div><hr><h3 id="bitmap-cpumask-—-Bitmap">bitmap / cpumask — Bitmap</h3><p>Kernel use <code>unsigned long</code> Implements bitmaps using arrays, providing an efficient set of bit operations.<code>cpumask</code> A special form of bitmap, specifically describing CPU sets.</p><p><strong>Header file:</strong> <code>&lt;linux/bitmap.h&gt;</code> / <code>&lt;linux/cpumask.h&gt;</code></p><p><strong>Core API (bitmap):</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>bitmap_zero(dst, nbits)</code></td><td>Clear all</td></tr><tr><td><code>bitmap_set(dst, pos, nbits)</code></td><td>Set bit</td></tr><tr><td><code>bitmap_clear(dst, pos, nbits)</code></td><td>Clear bit</td></tr><tr><td><code>bitmap_find_next_zero_area(buf, len, start, n, mask)</code></td><td>Find contiguous zero region</td></tr><tr><td><code>bitmap_and(dst, src1, src2, nbits)</code></td><td>Bitwise AND</td></tr><tr><td><code>bitmap_or(dst, src1, src2, nbits)</code></td><td>Bitwise OR</td></tr></tbody></table></div><p><strong>Core API (cpumask):</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>cpumask_set_cpu(cpu, mask)</code></td><td>Add CPU to mask</td></tr><tr><td><code>cpumask_clear_cpu(cpu, mask)</code></td><td>Remove CPU from mask</td></tr><tr><td><code>cpumask_test_cpu(cpu, mask)</code></td><td>Test if CPU is in mask</td></tr><tr><td><code>for_each_cpu(cpu, mask)</code></td><td>Iterate over CPUs in mask</td></tr><tr><td><code>cpumask_of(cpu)</code></td><td>Get mask for a single CPU</td></tr><tr><td><code>cpu_possible_mask</code></td><td>All possible CPUs in the system</td></tr><tr><td><code>cpu_online_mask</code></td><td>Currently online CPUs</td></tr><tr><td><code>cpu_present_mask</code></td><td>Currently present CPUs</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>IRQ affinity settings (specifying which CPUs handle interrupts)</li><li>Process’s <code>cpus_allowed</code>(setting which CPUs a process can run on)</li><li>DMA mask of memory nodes</li></ul><hr><h3 id="scatterlist-—-scatter-gather-list">scatterlist — scatter-gather list</h3><p><code>scatterlist</code> Used to describe<strong>non-contiguous memory regions</strong>, which is extremely common in DMA (Direct Memory Access) scenarios: linking scattered physical memory fragments into a whole for the DMA engine to process at once.</p><p><strong>Header file:</strong> <code>&lt;linux/scatterlist.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">scatterlist</span> &#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span>   page_link;   <span class="comment">// Encodes page + offset + chain information</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>    offset;      <span class="comment">// Offset within page</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>    length;      <span class="comment">// Data length</span></span><br><span class="line">    <span class="type">dma_addr_t</span>      dma_address; <span class="comment">// DMA address</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>    dma_length;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>sg_init_one(sg, buf, len)</code></td><td>Initialize single sg entry</td></tr><tr><td><code>sg_init_table(sg, nents)</code></td><td>Initialize sg table</td></tr><tr><td><code>sg_set_buf(sg, buf, len)</code></td><td>Set entry</td></tr><tr><td><code>sg_set_page(sg, page, len, offset)</code></td><td>Set page entry</td></tr><tr><td><code>sg_next(sg)</code></td><td>Get next entry</td></tr><tr><td><code>sg_nents(sg)</code></td><td>Calculate entry count</td></tr><tr><td><code>dma_map_sg(dev, sg, nents, dir)</code></td><td>Map sg table for DMA</td></tr><tr><td><code>dma_unmap_sg(dev, sg, nents, dir)</code></td><td>Unmap DMA</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">scatterlist</span> <span class="title">sg</span>[2];</span></span><br><span class="line">sg_init_table(sg, <span class="number">2</span>);</span><br><span class="line">sg_set_buf(&amp;sg[<span class="number">0</span>], buf1, len1);</span><br><span class="line">sg_set_buf(&amp;sg[<span class="number">1</span>], buf2, len2);</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> nents = dma_map_sg(dev, sg, <span class="number">2</span>, DMA_TO_DEVICE);</span><br><span class="line"><span class="comment">// ... initiate DMA transfer ...</span></span><br><span class="line">dma_unmap_sg(dev, sg, <span class="number">2</span>, DMA_TO_DEVICE);</span><br></pre></td></tr></table></figure><p><strong>Typical application in kernel:</strong></p><ul><li>Block device I/O (scatter-gather list in bio)</li><li>Network drivers (scatter-gather Tx/Rx)</li><li>Any data transfer involving DMA</li><li>Data buffers for encryption/decryption subsystems</li></ul><h2 id="Concurrency-and-synchronization">Concurrency and synchronization</h2><h3 id="atomic-t-—-atomic-variable">atomic_t — atomic variable</h3><p>Atomic operations in the kernel used for simple counting and flags, the foundation of lock-free programming. On 32-bit platforms <code>atomic_t</code> it is 32-bit, and on 64-bit platforms there is also <code>atomic64_t</code>。</p><p><strong>Header file:</strong> <code>&lt;linux/atomic.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">    <span class="type">int</span> counter;</span><br><span class="line">&#125; <span class="type">atomic_t</span>;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>atomic_read(v)</code></td><td>Read value</td></tr><tr><td><code>atomic_set(v, i)</code></td><td>Set value</td></tr><tr><td><code>atomic_inc(v)</code></td><td>Increment</td></tr><tr><td><code>atomic_dec(v)</code></td><td>decrement</td></tr><tr><td><code>atomic_add(i, v)</code></td><td>add</td></tr><tr><td><code>atomic_sub(i, v)</code></td><td>subtract</td></tr><tr><td><code>atomic_inc_return(v)</code></td><td>increment and return new value</td></tr><tr><td><code>atomic_dec_and_test(v)</code></td><td>decrement and test if zero</td></tr><tr><td><code>atomic_cmpxchg(v, old, new)</code></td><td>CAS operation</td></tr><tr><td><code>atomic_xchg(v, new)</code></td><td>swap and return old value</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>Reference counting (driver open count)</li><li>Statistical counters (network packet count, interrupt count)</li><li>Simple lock-free flags</li></ul><hr><h3 id="kref-refcount-t-—-reference-counting">kref / refcount_t — reference counting</h3><h4 id="kref">kref</h4><p>encapsulation <code>refcount_t</code>, providing reference count management for objects, working with <code>release</code> callback to automatically release resources when the count reaches zero.</p><p><strong>Header file:</strong> <code>&lt;linux/kref.h&gt;</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kref</span> &#123;</span></span><br><span class="line">    <span class="type">refcount_t</span> refcount;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">kref_init</span><span class="params">(<span class="keyword">struct</span> kref *kref)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">kref_get</span><span class="params">(<span class="keyword">struct</span> kref *kref)</span>;           <span class="comment">// Increment reference</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">kref_put</span><span class="params">(<span class="keyword">struct</span> kref *kref, <span class="type">void</span> (*release)(<span class="keyword">struct</span> kref *kref))</span>;  <span class="comment">// Decrement reference, call release when it reaches 0</span></span><br></pre></td></tr></table></figure><h4 id="refcount-t">refcount_t</h4><p><code>refcount_t</code> is <code>atomic_t</code> 's enhanced version, providing overflow protection—stops incrementing after reaching the maximum value, avoiding use-after-free vulnerabilities caused by reference count overflow.</p><p><strong>Header file:</strong> <code>&lt;linux/refcount.h&gt;</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">refcount_struct</span> &#123;</span></span><br><span class="line">    <span class="type">atomic_t</span> refs;</span><br><span class="line">&#125; <span class="type">refcount_t</span>;</span><br></pre></td></tr></table></figure><p><strong>Typical usage pattern:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">my_object</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kref</span> <span class="title">kref</span>;</span></span><br><span class="line">    <span class="comment">// ... other data</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">release_callback</span><span class="params">(<span class="keyword">struct</span> kref *kref)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">my_object</span> *<span class="title">obj</span> =</span> container_of(kref, <span class="keyword">struct</span> my_object, kref);</span><br><span class="line">    kfree(obj);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Acquire reference</span></span><br><span class="line"><span class="keyword">struct</span> my_object *<span class="title function_">get_object</span><span class="params">(<span class="keyword">struct</span> my_object *obj)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span> (obj)</span><br><span class="line">        kref_get(&amp;obj-&gt;kref);</span><br><span class="line">    <span class="keyword">return</span> obj;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Release reference</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">put_object</span><span class="params">(<span class="keyword">struct</span> my_object *obj)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span> (obj)</span><br><span class="line">        kref_put(&amp;obj-&gt;kref, release_callback);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li><code>struct kobject</code> 's reference count</li><li><code>struct device</code> 's lifecycle management</li><li>File descriptor (<code>struct file</code>）</li><li>Almost all kernel objects that require lifecycle management</li></ul><hr><h3 id="spinlock-t-—-Spinlock">spinlock_t — Spinlock</h3><p>The most fundamental of the Linux kernel<strong>spinlock</strong>, used for short critical section protection in SMP systems. When the holder is spinning on one CPU, executors on other CPUs are also spinning.</p><p><strong>Header file:</strong> <code>&lt;linux/spinlock.h&gt;</code></p><p><strong>Data structure (simplified):</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">spinlock</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">union</span> &#123;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">raw_spinlock</span> <span class="title">rlock</span>;</span></span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;;</span><br><span class="line">&#125; <span class="type">spinlock_t</span>;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>spin_lock_init(lock)</code></td><td>Dynamic initialization</td></tr><tr><td><code>DEFINE_SPINLOCK(lock)</code></td><td>Static definition + initialization</td></tr><tr><td><code>spin_lock(lock)</code></td><td>Acquire lock (disable kernel preemption)</td></tr><tr><td><code>spin_unlock(lock)</code></td><td>Release lock</td></tr><tr><td><code>spin_lock_irq(lock)</code></td><td>Acquire lock and disable local interrupts</td></tr><tr><td><code>spin_unlock_irq(lock)</code></td><td>Release lock and enable local interrupts</td></tr><tr><td><code>spin_lock_irqsave(lock, flags)</code></td><td>Acquire lock, save interrupt state</td></tr><tr><td><code>spin_unlock_irqrestore(lock, flags)</code></td><td>Release lock, restore interrupt state</td></tr><tr><td><code>spin_lock_bh(lock)</code></td><td>Acquire lock and disable bottom half</td></tr><tr><td><code>spin_trylock(lock)</code></td><td>Try to acquire lock (non-blocking)</td></tr><tr><td><code>spin_is_locked(lock)</code></td><td>Check lock status</td></tr></tbody></table></div><div class="note flat"><div class="note-title">warning</div><p>While holding a spinlock<strong>Must not sleep</strong>(Cannot call <code>kmalloc(GFP_KERNEL)</code>、<code>copy_from_user</code> operations that may block, etc.). This is one of the most common sources of bugs in the kernel.</p></div><p><strong>Selection guide:</strong></p><div class="table-wrap"><table><thead><tr><th>Scenario</th><th>API</th></tr></thead><tbody><tr><td>Between process contexts</td><td><code>spin_lock</code> / <code>spin_unlock</code></td></tr><tr><td>Between process and interrupt</td><td><code>spin_lock_irqsave</code> / <code>spin_unlock_irqrestore</code></td></tr><tr><td>Between different interrupts</td><td><code>spin_lock_irqsave</code> / <code>spin_unlock_irqrestore</code></td></tr><tr><td>Between process and bottom half</td><td><code>spin_lock_bh</code> / <code>spin_unlock_bh</code></td></tr></tbody></table></div><hr><h3 id="mutex-—-mutual-exclusion-lock">mutex — mutual exclusion lock</h3><p>Unlike spinlocks,<code>mutex</code> Yields the CPU and sleeps when the lock cannot be acquired, suitable for<strong>Critical sections that may sleep</strong>。</p><p><strong>Header file:</strong> <code>&lt;linux/mutex.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">mutex</span> &#123;</span></span><br><span class="line">    <span class="type">atomic_long_t</span>       owner;</span><br><span class="line">    <span class="type">raw_spinlock_t</span>      wait_lock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">wait_list</span>;</span>  <span class="comment">// Waiter queue</span></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>mutex_init(lock)</code></td><td>Dynamic initialization</td></tr><tr><td><code>DEFINE_MUTEX(lock)</code></td><td>Static definition</td></tr><tr><td><code>mutex_lock(lock)</code></td><td>Acquire lock (may sleep)</td></tr><tr><td><code>mutex_unlock(lock)</code></td><td>Release lock</td></tr><tr><td><code>mutex_lock_interruptible(lock)</code></td><td>Acquisition interruptible by signal</td></tr><tr><td><code>mutex_trylock(lock)</code></td><td>Try to acquire (non-blocking)</td></tr><tr><td><code>mutex_is_locked(lock)</code></td><td>Check status</td></tr></tbody></table></div><div class="note flat"><div class="note-title">warning</div><p><code>mutex</code> The locker must be responsible for unlocking (lock/unlock in different contexts is not allowed). The kernel strictly checks for this.</p></div><p><strong>Choosing between spinlock and mutex:</strong></p><div class="table-wrap"><table><thead><tr><th></th><th>spinlock</th><th>mutex</th></tr></thead><tbody><tr><td>When unable to acquire</td><td>Spin-wait</td><td>Sleep and yield CPU</td></tr><tr><td>Critical section</td><td>Short (nanosecond level)</td><td>Can be longer (millisecond level)</td></tr><tr><td>Can it sleep?</td><td>Absolutely not</td><td>Can</td></tr><tr><td>Interrupt context</td><td>Available</td><td>Not available</td></tr><tr><td>System overhead</td><td>Low</td><td>Higher (involves scheduling)</td></tr></tbody></table></div><hr><h3 id="completion-—-completion-count">completion — completion count</h3><p><code>completion</code> is implemented in the kernel<strong>a thread waiting for another thread to complete a task</strong>synchronization mechanism, which is lighter and has clearer semantics than semaphores.</p><p><strong>Header file:</strong> <code>&lt;linux/completion.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">completion</span> &#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> done;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">swait_queue_head</span> <span class="title">wait</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>DECLARE_COMPLETION(comp)</code></td><td>Static definition</td></tr><tr><td><code>init_completion(comp)</code></td><td>Dynamic initialization</td></tr><tr><td><code>wait_for_completion(comp)</code></td><td>Wait for completion (uninterruptible)</td></tr><tr><td><code>wait_for_completion_interruptible(comp)</code></td><td>Wait for completion (interruptible by signal)</td></tr><tr><td><code>wait_for_completion_timeout(comp, timeout)</code></td><td>Wait with timeout</td></tr><tr><td><code>complete(comp)</code></td><td>Wake up a waiter</td></tr><tr><td><code>complete_all(comp)</code></td><td>Wake up all waiters</td></tr><tr><td><code>try_wait_for_completion(comp)</code></td><td>Non-blocking attempt</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Thread A: waiting</span></span><br><span class="line">DECLARE_COMPLETION(done);</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">thread_a</span><span class="params">(<span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">    wait_for_completion(&amp;done);</span><br><span class="line">    pr_info(<span class="string">&quot;任务完成\n&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Thread B: notify after completion</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">thread_b</span><span class="params">(<span class="type">void</span> *data)</span></span><br><span class="line">&#123;</span><br><span class="line">    do_something();</span><br><span class="line">    complete(&amp;done);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>Kernel thread creation/destruction waiting</li><li>Device initialization completion notification</li><li>Asynchronous I/O completion notification</li><li>Module unloading waiting</li></ul><hr><h3 id="RCU-rcu-head-—-Read-Copy-Update">RCU (rcu_head) — Read-Copy-Update</h3><p>RCU (Read-Copy-Update) is an important<strong>lock-free synchronization mechanism</strong>, suitable for read-mostly scenarios. Readers are completely lock-free, writers copy first and then update, and wait for all readers to finish before reclaiming old data.</p><p><strong>Header file:</strong> <code>&lt;linux/rcupdate.h&gt;</code> / <code>&lt;linux/srcu.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">rcu_head</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">callback_head</span> *<span class="title">next</span>;</span></span><br><span class="line">    <span class="type">void</span> (*func)(<span class="keyword">struct</span> callback_head *head);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>rcu_read_lock()</code></td><td>Reader enters critical section</td></tr><tr><td><code>rcu_read_unlock()</code></td><td>Reader leaves critical section</td></tr><tr><td><code>call_rcu(head, func)</code></td><td>Register reclaim callback</td></tr><tr><td><code>synchronize_rcu()</code></td><td>Wait for all readers to complete (blocking)</td></tr><tr><td><code>rcu_assign_pointer(p, v)</code></td><td>Writer updates pointer</td></tr><tr><td><code>rcu_dereference(p)</code></td><td>Reader dereferences pointer</td></tr><tr><td><code>kfree_rcu(ptr, rcu_field)</code></td><td>RCU-safe memory release</td></tr></tbody></table></div><p><strong>Typical pattern:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Reader — completely lock-free</span></span><br><span class="line">rcu_read_lock();</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">p</span> =</span> rcu_dereference(global_ptr);</span><br><span class="line"><span class="keyword">if</span> (p)</span><br><span class="line">    do_something(p);</span><br><span class="line">rcu_read_unlock();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Writer — copy + update</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">old</span> =</span> global_ptr;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">my_data</span> *<span class="title">new</span> =</span> kmemdup(old, <span class="keyword">sizeof</span>(*old), GFP_KERNEL);</span><br><span class="line">update_data(new);</span><br><span class="line">rcu_assign_pointer(global_ptr, new);</span><br><span class="line">call_rcu(&amp;old-&gt;rcu, my_free_callback);</span><br></pre></td></tr></table></figure><p><strong>Typical application in the kernel:</strong></p><ul><li>Network routing table lookup</li><li>File system dentry cache</li><li><code>radix_tree</code> / <code>xarray</code> Lock-free lookup</li><li><code>fdtable</code>Expansion of (file descriptor table)</li></ul><hr><hr><h2 id="Waiting-and-scheduling">Waiting and scheduling</h2><h3 id="wait-queue-—-Wait-queue">wait_queue — Wait queue</h3><p>A wait queue is a more general waiting mechanism: a process puts itself into the wait queue and goes to sleep, and is woken up when the condition is met.</p><p><strong>Header file:</strong> <code>&lt;linux/wait.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">wait_queue_head</span> &#123;</span></span><br><span class="line">    <span class="type">spinlock_t</span>          lock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">head</span>;</span>     <span class="comment">// Linked list of wait entries</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">wait_queue_entry</span> &#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>        flags;</span><br><span class="line">    <span class="type">void</span>               *private;  <span class="comment">// Usually points to task_struct</span></span><br><span class="line">    <span class="type">wait_queue_func_t</span>   func;     <span class="comment">// Wakeup callback (usually autoremove)_wake_function）</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">entry</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>DECLARE_WAIT_QUEUE_HEAD(wq)</code></td><td>Static definition</td></tr><tr><td><code>init_waitqueue_head(wq)</code></td><td>Dynamic initialization</td></tr><tr><td><code>wait_event(wq, condition)</code></td><td>Wait until condition is true</td></tr><tr><td><code>wait_event_interruptible(wq, condition)</code></td><td>Wait interruptible by signal</td></tr><tr><td><code>wait_event_timeout(wq, condition, timeout)</code></td><td>Wait with timeout</td></tr><tr><td><code>wake_up(wq)</code></td><td>Wake up all waiters</td></tr><tr><td><code>wake_up_interruptible(wq)</code></td><td>Wake up TASK_INTERRUPTIBLE waiters</td></tr><tr><td><code>wake_up_nr(wq, nr)</code></td><td>Wake up nr waiters</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">DECLARE_WAIT_QUEUE_HEAD(wq);</span><br><span class="line"><span class="type">int</span> data_ready = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Wait side</span></span><br><span class="line">wait_event_interruptible(wq, data_ready != <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Wakeup side</span></span><br><span class="line">data_ready = <span class="number">1</span>;</span><br><span class="line">wake_up_interruptible(&amp;wq);</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>Process state switching (TASK_INTERRUPTIBLE / TASK_UNINTERRUPTIBLE）</li><li>Blocking I/O in device drivers (read/write waiting for data)</li><li>Read/write waiting for Pipe, Socket</li></ul><hr><h3 id="work-struct-workqueue-—-Work-queue">work_struct / workqueue — Work queue</h3><p>Work queue will<strong>Task deferred to process context</strong>execution, which is one of the common methods for interrupt bottom half processing.</p><p><strong>Header file:</strong> <code>&lt;linux/workqueue.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">work_struct</span> &#123;</span></span><br><span class="line">    <span class="type">atomic_long_t</span> data;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">entry</span>;</span></span><br><span class="line">    <span class="type">work_func_t</span> func;  <span class="comment">// Work function</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Work function signature:</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="title function_">void</span> <span class="params">(*<span class="type">work_func_t</span>)</span><span class="params">(<span class="keyword">struct</span> work_struct *work)</span>;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>DECLARE_WORK(work, func)</code></td><td>Static definition</td></tr><tr><td><code>INIT_WORK(work, func)</code></td><td>Dynamic initialization</td></tr><tr><td><code>schedule_work(work)</code></td><td>Schedule to system work queue</td></tr><tr><td><code>schedule_delayed_work(dwork, delay)</code></td><td>Delayed scheduling</td></tr><tr><td><code>queue_work(wq, work)</code></td><td>Schedule to specified work queue</td></tr><tr><td><code>cancel_work_sync(work)</code></td><td>Cancel and wait for completion</td></tr><tr><td><code>flush_work(work)</code></td><td>Wait for work completion</td></tr><tr><td><code>alloc_ordered_workqueue(name, flags)</code></td><td>Create ordered workqueue</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">my_work_handler</span><span class="params">(<span class="keyword">struct</span> work_struct *work)</span></span><br><span class="line">&#123;</span><br><span class="line">    pr_info(<span class="string">&quot;工作在进程上下文执行\n&quot;</span>);</span><br><span class="line">    <span class="comment">// Can sleep here!</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">DECLARE_WORK(my_work, my_work_handler);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Trigger (e.g., in interrupt handler)</span></span><br><span class="line">schedule_work(&amp;my_work);</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>Interrupt bottom-half processing</li><li>Deferred initialization of device drivers</li><li>Packet processing in the network stack</li><li>GPU driver command submission</li></ul><hr><h3 id="timer-list-—-kernel-timer">timer_list — kernel timer</h3><p>Used after a specified time<strong>execute a callback function</strong>(softirq context), with jiffies-level precision (usually 1ms~10ms). For higher precision, use <code>hrtimer</code>。</p><p><strong>Header file:</strong> <code>&lt;linux/timer.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">hlist_node</span>   <span class="title">entry</span>;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span>       expires;  <span class="comment">// Expiration time (jiffies)</span></span><br><span class="line">    <span class="type">void</span>                (*function)(<span class="keyword">struct</span> timer_list *);</span><br><span class="line">    u32                 flags;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>timer_setup(timer, callback, flags)</code></td><td>Initialize timer</td></tr><tr><td><code>mod_timer(timer, expires)</code></td><td>Modify expiration time</td></tr><tr><td><code>add_timer(timer)</code></td><td>Add timer</td></tr><tr><td><code>del_timer(timer)</code></td><td>Delete timer</td></tr><tr><td><code>del_timer_sync(timer)</code></td><td>Synchronous delete (wait for handler to complete)</td></tr><tr><td><code>timer_pending(timer)</code></td><td>Check if submitted</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">my_timer_callback</span><span class="params">(<span class="keyword">struct</span> timer_list *t)</span></span><br><span class="line">&#123;</span><br><span class="line">    pr_info(<span class="string">&quot;定时器到期\n&quot;</span>);</span><br><span class="line">    <span class="comment">// Periodic timer: Reset</span></span><br><span class="line">    mod_timer(t, jiffies + msecs_to_jiffies(<span class="number">500</span>));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timer_list</span> <span class="title">my_timer</span>;</span></span><br><span class="line">timer_setup(&amp;my_timer, my_timer_callback, <span class="number">0</span>);</span><br><span class="line">mod_timer(&amp;my_timer, jiffies + msecs_to_jiffies(<span class="number">500</span>));</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>TCP retransmission timer, keepalive timer</li><li>Watchdog timer</li><li>Device driver polling</li><li>LED Blink Control</li></ul><hr><h3 id="hrtimer-—-High-Resolution-Timer">hrtimer — High-Resolution Timer</h3><p><code>hrtimer</code> Provides<strong>Nanosecond-level</strong>precision timer, managed at the bottom layer based on a red-black tree. It is the foundation of the modern Linux timer subsystem.</p><p><strong>Header file:</strong> <code>&lt;linux/hrtimer.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hrtimer</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">timerqueue_node</span>      <span class="title">node</span>;</span>   <span class="comment">// Red-black tree node</span></span><br><span class="line">    <span class="type">ktime_t</span>                     _softexpires;</span><br><span class="line">    <span class="keyword">enum</span> <span class="title function_">hrtimer_restart</span>        <span class="params">(*function)</span><span class="params">(<span class="keyword">struct</span> hrtimer *)</span>;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>hrtimer_init(timer, clock_id, mode)</code></td><td>Initialization</td></tr><tr><td><code>hrtimer_start(timer, time, mode)</code></td><td>Start timer</td></tr><tr><td><code>hrtimer_cancel(timer)</code></td><td>Cancel timer</td></tr><tr><td><code>hrtimer_forward_now(timer, interval)</code></td><td>Advance forward from the current time</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">enum</span> hrtimer_restart <span class="title function_">my_hrtimer_cb</span><span class="params">(<span class="keyword">struct</span> hrtimer *timer)</span></span><br><span class="line">&#123;</span><br><span class="line">    pr_info(<span class="string">&quot;高精度定时器到期\n&quot;</span>);</span><br><span class="line">    hrtimer_forward_now(timer, ns_to_ktime(<span class="number">1000000</span>));  <span class="comment">// 1ms</span></span><br><span class="line">    <span class="keyword">return</span> HRTIMER_RESTART;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">hrtimer</span> <span class="title">hr_timer</span>;</span></span><br><span class="line">hrtimer_init(&amp;hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);</span><br><span class="line">hr_timer.function = my_hrtimer_cb;</span><br><span class="line">hrtimer_start(&amp;hr_timer, ns_to_ktime(<span class="number">1000000</span>), HRTIMER_MODE_REL);</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>Periodic tick of the process scheduler</li><li>POSIX timers</li><li>High-precision sleep (<code>usleep_range</code>）</li><li>Precise delay control of network packets</li></ul><hr><hr><h2 id="Device-model-and-notifications">Device model and notifications</h2><h3 id="kobject-kset-—-kernel-object-model">kobject / kset — kernel object model</h3><p><code>kobject</code> is the cornerstone of the Linux <strong>device driver model</strong>, providing unified reference counting, sysfs representation, and hotplug event support for all kernel objects.</p><p><strong>Header file:</strong> <code>&lt;linux/kobject.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> &#123;</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span>      *name;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">entry</span>;</span>       <span class="comment">// Linked list linked into kset</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kobject</span>      *<span class="title">parent</span>;</span>     <span class="comment">// Parent object</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kset</span>         *<span class="title">kset</span>;</span>       <span class="comment">// Owning kset</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kobj_type</span>    *<span class="title">ktype</span>;</span>      <span class="comment">// Type descriptor (including sysfs operations)</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kernfs_node</span>  *<span class="title">sd</span>;</span>        <span class="comment">// sysfs directory node</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kref</span>         <span class="title">kref</span>;</span>        <span class="comment">// Reference count</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> state_initialized:<span class="number">1</span>;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">kset</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">list</span>;</span>           <span class="comment">// All kobjects belonging to this kset</span></span><br><span class="line">    <span class="type">spinlock_t</span> list_lock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">kobject</span> <span class="title">kobj</span>;</span>             <span class="comment">// Itself is also a kobject</span></span><br><span class="line">    <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">kset_uevent_ops</span> *<span class="title">uevent_ops</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>kobject_init(obj, ktype)</code></td><td>Initialize kobject</td></tr><tr><td><code>kobject_add(obj, parent, fmt, ...)</code></td><td>Add to sysfs</td></tr><tr><td><code>kobject_init_and_add(obj, ktype, parent, fmt, ...)</code></td><td>Initialize + Add</td></tr><tr><td><code>kobject_put(obj)</code></td><td>Decrement reference count</td></tr><tr><td><code>kobject_get(obj)</code></td><td>Increment reference count</td></tr><tr><td><code>kobject_uevent(obj, action)</code></td><td>Send uevent to userspace</td></tr><tr><td><code>kset_register(kset)</code></td><td>Register kset</td></tr><tr><td><code>kobject_create_and_add(name, parent)</code></td><td>Quickly create kobject</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li><code>/sys</code> Each directory and file in the file system</li><li><code>struct device</code>、<code>struct driver</code>、<code>struct bus_type</code> base classes of the device model, etc.</li><li><code>uevent</code> Hotplug events (e.g., USB drive insertion notifying udev)</li></ul><hr><h3 id="notifier-block-—-Notifier-Chain">notifier_block — Notifier Chain</h3><p>The Notifier Chain is in the kernel<strong>publish-subscribe</strong>pattern implementation: a subsystem publishes events, and other interested modules register callbacks to receive notifications.</p><p><strong>Header file:</strong> <code>&lt;linux/notifier.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">notifier_block</span> &#123;</span></span><br><span class="line">    <span class="type">notifier_fn_t</span> notifier_call;    <span class="comment">// Callback function</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">notifier_block</span> __<span class="title">rcu</span> *<span class="title">next</span>;</span>  <span class="comment">// Next in linked list</span></span><br><span class="line">    <span class="type">int</span> priority;                   <span class="comment">// Priority</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>blocking_notifier_chain_register(head, nb)</code></td><td>Register notification block</td></tr><tr><td><code>blocking_notifier_chain_unregister(head, nb)</code></td><td>Unregister</td></tr><tr><td><code>blocking_notifier_call_chain(head, val, v)</code></td><td>Raise notification</td></tr><tr><td><code>raw_notifier_chain_register(head, nb)</code></td><td>Register (atomic context safe)</td></tr><tr><td><code>atomic_notifier_chain_register(head, nb)</code></td><td>Register (atomic context)</td></tr></tbody></table></div><p><strong>Notification chain type:</strong></p><div class="table-wrap"><table><thead><tr><th>Type</th><th>Callback context</th><th>Can block?</th></tr></thead><tbody><tr><td><code>atomic_notifier_chain</code></td><td>Atomic context (interrupt/spinlock)</td><td>No</td></tr><tr><td><code>blocking_notifier_chain</code></td><td>Process context</td><td>Yes</td></tr><tr><td><code>raw_notifier_chain</code></td><td>Any context (caller responsible)</td><td>Depends on caller</td></tr><tr><td><code>SRCU_notifier_chain</code></td><td>Process context (SRCU protected)</td><td>is</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>Kernel panic notification</li><li>CPU hotplug events</li><li>Network device events (netdev registration/deregistration)</li><li>System reboot/suspend notification</li><li>Out-of-memory (OOM) notification</li></ul><hr><h2 id="Memory-management-and-caching">Memory management and caching</h2><h3 id="kfifo-—-kernel-FIFO-queue">kfifo — kernel FIFO queue</h3><p><code>kfifo</code> is a<strong>lock-free circular buffer</strong>(circular buffer), providing lock-free communication for producer/consumer single-reader/single-writer (multi-reader/multi-writer requires external synchronization).</p><p><strong>Header file:</strong> <code>&lt;linux/kfifo.h&gt;</code></p><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>DECLARE_KFIFO(fifo, type, size)</code></td><td>Static Definition</td></tr><tr><td><code>kfifo_alloc(fifo, size, gfp)</code></td><td>Dynamic Allocation</td></tr><tr><td><code>kfifo_put(fifo, val)</code></td><td>Enqueue an Element</td></tr><tr><td><code>kfifo_get(fifo, val)</code></td><td>Dequeue an Element</td></tr><tr><td><code>kfifo_in(fifo, buf, n)</code></td><td>Enqueue Multiple Bytes</td></tr><tr><td><code>kfifo_out(fifo, buf, n)</code></td><td>Dequeue Multiple Bytes</td></tr><tr><td><code>kfifo_is_empty(fifo)</code></td><td>Is Empty</td></tr><tr><td><code>kfifo_is_full(fifo)</code></td><td>Is Full</td></tr><tr><td><code>kfifo_len(fifo)</code></td><td>Number of Used Elements</td></tr><tr><td><code>kfifo_reset(fifo)</code></td><td>Clear Queue</td></tr><tr><td><code>kfifo_free(fifo)</code></td><td>Free Memory</td></tr></tbody></table></div><p><strong>Usage Example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">DECLARE_KFIFO(fifo, <span class="type">int</span>, <span class="number">32</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Enqueue</span></span><br><span class="line"><span class="type">int</span> val = <span class="number">42</span>;</span><br><span class="line">kfifo_put(&amp;fifo, val);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Dequeue</span></span><br><span class="line"><span class="type">int</span> out;</span><br><span class="line"><span class="keyword">if</span> (kfifo_get(&amp;fifo, &amp;out))</span><br><span class="line">    pr_info(<span class="string">&quot;got: %d\n&quot;</span>, out);</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>Serial port driver transmit/receive buffers</li><li>Audio driver PCM buffer</li><li>Kernel log buffer (printk ring buffer)</li></ul><hr><h3 id="percpu-—-Per-CPU-variables">percpu — Per-CPU variables</h3><p>Per-CPU variables allocate<strong>independent memory copies for each CPU</strong>, CPUs can access their own copies without locking, and cache utilization is extremely high (variables are in the CPU’s local cache).</p><p><strong>Header file:</strong> <code>&lt;linux/percpu.h&gt;</code></p><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>DEFINE_PER_CPU(type, name)</code></td><td>Static definition</td></tr><tr><td><code>alloc_percpu(type)</code></td><td>Dynamic allocation</td></tr><tr><td><code>per_cpu(var, cpu)</code></td><td>Access the copy of a specified CPU</td></tr><tr><td><code>get_cpu_var(var)</code></td><td>Get the copy of the current CPU (preemption disabled)</td></tr><tr><td><code>put_cpu_var(var)</code></td><td>Combined with get_cpu_var, restore preemption</td></tr><tr><td><code>this_cpu_ptr(ptr)</code></td><td>Get pointer to this CPU’s copy</td></tr><tr><td><code>per_cpu_ptr(ptr, cpu)</code></td><td>Get pointer to the specified CPU’s copy</td></tr><tr><td><code>for_each_possible_cpu(cpu)</code></td><td>Iterate over all CPUs</td></tr></tbody></table></div><p><strong>Usage example:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">static</span> <span class="title function_">DEFINE_PER_CPU</span><span class="params">(<span class="type">int</span>, my_counter)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Increment this CPU&#x27;s counter — no locking required</span></span><br><span class="line"><span class="type">int</span> cpu = get_cpu();</span><br><span class="line">per_cpu(my_counter, cpu)++;</span><br><span class="line">put_cpu();</span><br><span class="line"></span><br><span class="line"><span class="comment">// A more concise way (better performance)</span></span><br><span class="line">this_cpu_inc(my_counter);</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>Statistical counters (network packet count, interrupt count)</li><li>Per-CPU cache for memory allocators (slab/slub)</li><li>Per-CPU state for RCU</li><li>Per-CPU runqueue for the scheduler</li></ul><hr><h3 id="circ-buf-—-circular-buffer-macros">circ_buf — circular buffer macros</h3><p>A set of simple macros for using ordinary character arrays as circular buffers. Commonly used to implement lightweight producer/consumer queues.</p><p><strong>Header file:</strong> <code>&lt;linux/circ_buf.h&gt;</code></p><p><strong>Data structure:</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">circ_buf</span> &#123;</span></span><br><span class="line">    <span class="type">char</span> *buf;</span><br><span class="line">    <span class="type">int</span> head;   <span class="comment">// Producer write position</span></span><br><span class="line">    <span class="type">int</span> tail;   <span class="comment">// Consumer read position</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core macro:</strong></p><div class="table-wrap"><table><thead><tr><th>Macro</th><th>Description</th></tr></thead><tbody><tr><td><code>CIRC_SPACE(head, tail, size)</code></td><td>Available space</td></tr><tr><td><code>CIRC_CNT(head, tail, size)</code></td><td>Used bytes</td></tr><tr><td><code>CIRC_SPACE_TO_END(head, tail, size)</code></td><td>Contiguous space to the end of the buffer</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>TTY driver line discipline buffer</li><li>Simple serial port driver</li></ul><hr><h3 id="flex-array-—-flexible-array">flex_array — flexible array</h3><p><code>flex_array</code> Allows creating<strong>Array spanning multiple pages</strong>, but each element has a fixed size. Compared to a single <code>kmalloc</code> large chunk of memory,<code>flex_array</code> it is more tolerant of small memory fragments (because each element is distributed across different pages).</p><div class="note flat"><div class="note-title">warning</div><p>Starting from Linux 5.10,<code>flex_array</code> it has been marked as deprecated, and it is recommended to use ordinary <code>kmalloc_array</code> or <code>kvmalloc_array</code> instead.</p></div><p><strong>Header file:</strong> <code>&lt;linux/flex_array.h&gt;</code>(deleted)</p><p><strong>Alternative:</strong> <code>kvmalloc_array(n, size, GFP_KERNEL)</code> will automatically select <code>kmalloc</code> or <code>vmalloc</code>。</p><hr><h3 id="page-—-physical-page-descriptor">page — physical page descriptor</h3><p><code>struct page</code> is in Linux memory management<strong>The most important data structure</strong>, each physical memory page has a corresponding <code>page</code> struct.</p><p><strong>Header file:</strong> <code>&lt;linux/mm_types.h&gt;</code></p><p><strong>Data structure (greatly simplified):</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">page</span> &#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> flags;         <span class="comment">// Page flags (PG_locked, PG_dirty, etc.)</span></span><br><span class="line">    <span class="class"><span class="keyword">union</span> &#123;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">            <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">lru</span>;</span>    <span class="comment">// LRU list</span></span><br><span class="line">            <span class="class"><span class="keyword">struct</span> <span class="title">address_space</span> *<span class="title">mapping</span>;</span>  <span class="comment">// Associated file mapping</span></span><br><span class="line">            <span class="type">pgoff_t</span> index;           <span class="comment">// Offset within page</span></span><br><span class="line">            <span class="type">unsigned</span> <span class="type">long</span> private;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="comment">// ... SLUB/slab related fields</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">refcount_t</span> _refcount;        <span class="comment">// Reference count</span></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Core API (partial):</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>alloc_pages(gfp_mask, order)</code></td><td>Allocate 2^order pages</td></tr><tr><td><code>__free_pages(page, order)</code></td><td>Free page</td></tr><tr><td><code>get_page(page)</code></td><td>Increment reference count</td></tr><tr><td><code>put_page(page)</code></td><td>Decrement reference count</td></tr><tr><td><code>page_to_pfn(page)</code></td><td>Get page frame number</td></tr><tr><td><code>pfn_to_page(pfn)</code></td><td>Page frame number to page</td></tr><tr><td><code>kmap(page)</code></td><td>Map to kernel address space</td></tr><tr><td><code>kunmap(page)</code></td><td>Unmap</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>Page Cache</li><li>Underlying foundation of SLUB/SLAB allocator</li><li>User space page table mapping (page fault handling)</li></ul><hr><h3 id="mm-struct-vm-area-struct-—-process-address-space">mm_struct / vm_area_struct — process address space</h3><h4 id="mm-struct-—-memory-descriptor">mm_struct — memory descriptor</h4><p>Describes a process’s<strong>complete virtual address space</strong>, each process has a unique <code>mm_struct</code>(Shareable between threads).</p><p><strong>Header file:</strong> <code>&lt;linux/mm_types.h&gt;</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">mm_struct</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">maple_tree</span>   <span class="title">mm_mt</span>;</span>          <span class="comment">// VMA maple tree (6.1+)</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">vm_area_struct</span> *<span class="title">mmap</span>;</span>        <span class="comment">// VMA linked list head</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> task_size;            <span class="comment">// Address space size</span></span><br><span class="line">    <span class="type">pgd_t</span> *pgd;                         <span class="comment">// Page Global Directory</span></span><br><span class="line">    <span class="type">atomic_t</span> mm_users;                  <span class="comment">// User count</span></span><br><span class="line">    <span class="type">atomic_t</span> mm_count;                  <span class="comment">// Reference count</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> total_vm;             <span class="comment">// Total page count</span></span><br><span class="line">    <span class="type">spinlock_t</span> page_table_lock;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span> <span class="title">mmlist</span>;</span>            <span class="comment">// Global mm_struct linked list</span></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h4 id="vm-area-struct-—-Virtual-Memory-Area">vm_area_struct — Virtual Memory Area</h4><p>Describes a<strong>contiguous virtual address range</strong>, where each range has the same protection attributes and mapping type.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">vm_area_struct</span> &#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> vm_start;             <span class="comment">// Start address</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> vm_end;               <span class="comment">// End address (exclusive)</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">vm_area_struct</span> *<span class="title">vm_next</span>;</span>     <span class="comment">// Next in linked list</span></span><br><span class="line">    <span class="type">pgprot_t</span> vm_page_prot;              <span class="comment">// Page protection</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> vm_flags;             <span class="comment">// VM_READ, VM_WRITE, VM_EXEC, etc.</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">rb_node</span> <span class="title">vm_rb</span>;</span>               <span class="comment">// Red-black tree node (legacy)</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">mm_struct</span> *<span class="title">vm_mm</span>;</span>            <span class="comment">// Owning mm_struct</span></span><br><span class="line">    <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">vm_operations_struct</span> *<span class="title">vm_ops</span>;</span>  <span class="comment">// Operations function table</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">file</span> *<span class="title">vm_file</span>;</span>               <span class="comment">// Mapped file</span></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>Typical applications in the kernel:</strong></p><ul><li>Page fault handler</li><li><code>mmap()</code> / <code>munmap()</code> System call</li><li><code>/proc/&lt;pid&gt;/maps</code> Information source</li></ul><hr><hr><h2 id="Network">Network</h2><h3 id="sk-buff-—-Socket-buffer">sk_buff — Socket buffer</h3><p><code>sk_buff</code>(usually abbreviated as <code>skb</code>) is Linux <strong>network subsystem</strong>’s core data structure, representing a network packet. It runs through the entire network stack: from network card driver reception to application layer transmission, all use <code>sk_buff</code> as the carrier.</p><p><strong>Header file:</strong> <code>&lt;linux/skbuff.h&gt;</code></p><p><strong>Data structure (simplified):</strong></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sk_buff</span> &#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">union</span> &#123;</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">            <span class="class"><span class="keyword">struct</span> <span class="title">sk_buff</span>      *<span class="title">next</span>;</span>   <span class="comment">// Doubly linked list</span></span><br><span class="line">            <span class="class"><span class="keyword">struct</span> <span class="title">sk_buff</span>      *<span class="title">prev</span>;</span></span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="class"><span class="keyword">struct</span> <span class="title">list_head</span>    <span class="title">list</span>;</span></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sock</span>     *<span class="title">sk</span>;</span></span><br><span class="line">    <span class="type">ktime_t</span>         tstamp;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">net_device</span>   *<span class="title">dev</span>;</span></span><br><span class="line">    <span class="type">char</span>            cb[<span class="number">48</span>] __aligned(<span class="number">8</span>);  <span class="comment">// Private data for each layer</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>    len,           <span class="comment">// Total data length</span></span><br><span class="line">                    data_len;      <span class="comment">// Non-linear data length</span></span><br><span class="line">    __u16           mac_len,</span><br><span class="line">                    hdr_len;</span><br><span class="line">    <span class="comment">// ... followed by pointers like head, data, tail, end, etc.</span></span><br><span class="line">    <span class="type">sk_buff_data_t</span>      tail;</span><br><span class="line">    <span class="type">sk_buff_data_t</span>      end;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">char</span>       *head, *data;</span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span>        truesize;</span><br><span class="line">    <span class="type">refcount_t</span>          users;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><code>sk_buff</code> Uses a four-pointer model to manage data space:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">head  data        tail  end</span><br><span class="line"> |     |           |     |</span><br><span class="line"> v     v           v     v</span><br><span class="line">+-----+-----------+-----+</span><br><span class="line">|headroom|  data   |tailroom|</span><br><span class="line">+-----+-----------+-----+</span><br></pre></td></tr></table></figure><p><strong>Core API:</strong></p><div class="table-wrap"><table><thead><tr><th>API</th><th>Description</th></tr></thead><tbody><tr><td><code>alloc_skb(size, gfp)</code></td><td>Allocate skb</td></tr><tr><td><code>skb_put(skb, len)</code></td><td>Append data to the tail</td></tr><tr><td><code>skb_push(skb, len)</code></td><td>Add data to the head (add protocol header)</td></tr><tr><td><code>skb_pull(skb, len)</code></td><td>Remove data from the head (strip protocol header)</td></tr><tr><td><code>skb_clone(skb, gfp)</code></td><td>Clone skb (share data)</td></tr><tr><td><code>skb_copy(skb, gfp)</code></td><td>Deep copy (copy data)</td></tr><tr><td><code>kfree_skb(skb)</code></td><td>Free skb</td></tr><tr><td><code>skb_queue_head(list, skb)</code></td><td>Enqueue to the head</td></tr><tr><td><code>skb_dequeue(list)</code></td><td>Dequeue</td></tr></tbody></table></div><p><strong>Typical applications in the kernel:</strong></p><ul><li>Packet carrier for the entire network stack</li><li>TUN/TAP virtual network card</li><li>Packet filtering for Netfilter / iptables</li></ul><h1 id="References">References</h1><div class="reference-source"><span class="hidden-anchor" id="referfrom_[1]"></span><a class="reference-anchor" href="#referto_[1]">[1]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="linux listDetailed explanation" href="https://www.cnblogs.com/xinghuo123/p/13113422.html">linux listDetailed explanation</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[2]"></span><a class="reference-anchor" href="#referto_[2]">[2]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Linux：KernelhashTable——hlist" href="https://zhuanlan.zhihu.com/p/360217911">Linux：KernelhashTable——hlist</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[3]"></span><a class="reference-anchor" href="#referto_[3]">[3]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="LinuxRed-Black Tree in（rbtree）" href="https://www.kernel.org/doc/html/latest/translations/zh_CN/core-api/rbtree.html">LinuxRed-Black Tree in（rbtree）</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[4]"></span><a class="reference-anchor" href="#referto_[4]">[4]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Linux：radixImplementation Analysis" href="https://www.cnblogs.com/JiMoKuangXiangQu/articles/18812729">Linux：radixImplementation Analysis</a></div>]]></content>
    
    
    <summary type="html">This article introduces the core data structures with high practical usage frequency in the Linux 6.x kernel, detailing the definitions, core APIs, and typical use cases of structures such as doubly linked circular lists, hash linked lists, red-black trees, radix trees, extensible arrays, and priority linked lists.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>ClaudeCode</title>
    <link href="https://even629.com/en/posts/202605241/"/>
    <id>https://even629.com/en/posts/202605241/</id>
    <published>2026-05-24T02:10:13.000Z</published>
    <updated>2026-05-24T02:10:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-05-24</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces the download, installation, and editor integration methods of Claude Code, detailing how to configure and use it with the DeepSeek API in VSCode and Emacs. Additionally, it discusses Claude Code's Skill extension mechanism, the MCP model context protocol, as well as the installation of related Skills and recommended plugins.</blockquote><hr><h1 id="ClaudeCode">ClaudeCode</h1><p>Download Claude Code, requires Node.js</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># It&#x27;s best to change the source</span></span><br><span class="line">npm config <span class="built_in">set</span> registry https://registry.npmmirror.com</span><br><span class="line">npm install -g @anthropic-ai/claude-code</span><br><span class="line"></span><br><span class="line">claude --version</span><br><span class="line"></span><br><span class="line"><span class="comment"># Restore the session in the current directory</span></span><br><span class="line">claude -c</span><br></pre></td></tr></table></figure><h1 id="DeepSeek">DeepSeek</h1><p>Choose DeepSeek here because its tokens are cheaper and don’t require an external network connection. Click the link below to apply for an API key</p><div class="tag link"><a class="link-card" title="DeepSeek Open Platform" href="https://platform.deepseek.com/api_keys"><div class="left"><img loading="lazy" src="https://api-docs.deepseek.com/zh-cn/img/favicon.svg"/></div><div class="right"><p class="text">DeepSeek Open Platform</p><p class="url">https://platform.deepseek.com/api_keys</p></div></a></div><h1 id="Editor-Integration">Editor Integration</h1><h2 id="Vscode">Vscode</h2><p>Download the plugin:<code>Claude Code for VS Code</code>Anthropic anthropic.com, then find it in the settings<code>@ext:Anthropic.claude-code</code>under<code>ClaudeCode: Environment Variables</code>Click<code>Edit in settings.json</code></p><p>Refer to the official documentation to set environment variables</p><div class="tag link"><a class="link-card" title="IntegrationClaude Code" href="https://api-docs.deepseek.com/zh-cn/quick_start/agent_integrations/claude_code"><div class="left"><img loading="lazy" src="https://api-docs.deepseek.com/zh-cn/img/favicon.svg"/></div><div class="right"><p class="text">IntegrationClaude Code</p><p class="url">https://api-docs.deepseek.com/zh-cn/quick_start/agent_integrations/claude_code</p></div></a></div><p>As follows:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;claudeCode.environmentVariables&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ANTHROPIC_BASE_URL&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;https://api.deepseek.com/anthropic&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ANTHROPIC_AUTH_TOKEN&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&lt;你的 DeepSeek API Key&gt;&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ANTHROPIC_MODEL&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;deepseek-v4-pro[1m]&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ANTHROPIC_DEFAULT_OPUS_MODEL&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;deepseek-v4-pro[1m]&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ANTHROPIC_DEFAULT_SONNET_MODEL&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;deepseek-v4-pro[1m]&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ANTHROPIC_DEFAULT_HAIKU_MODEL&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;deepseek-v4-flash&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;CLAUDE_CODE_SUBAGENT_MODEL&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;deepseek-v4-flash&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;CLAUDE_CODE_EFFORT_LEVEL&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="string">&quot;max&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">]</span><span class="punctuation">,</span></span><br></pre></td></tr></table></figure><p>After that, open the Claude Code plugin in VSCode and it will be ready to use.</p><p>You can also set environment variables in Windows PowerShell. First, open PowerShell with administrator privileges, then</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">code <span class="variable">$PROFILE</span></span><br></pre></td></tr></table></figure><p>Then write the environment variables from the official documentation, so that these environment variables are loaded every time PowerShell is opened.</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$env:ANTHROPIC_BASE_URL</span>=<span class="string">&quot;https://api.deepseek.com/anthropic&quot;</span></span><br><span class="line"><span class="variable">$env:ANTHROPIC_AUTH_TOKEN</span>=<span class="string">&quot;&lt;你的 DeepSeek API Key&gt;&quot;</span></span><br><span class="line"><span class="variable">$env:ANTHROPIC_MODEL</span>=<span class="string">&quot;deepseek-v4-pro[1m]&quot;</span></span><br><span class="line"><span class="variable">$env:ANTHROPIC_DEFAULT_OPUS_MODEL</span>=<span class="string">&quot;deepseek-v4-pro[1m]&quot;</span></span><br><span class="line"><span class="variable">$env:ANTHROPIC_DEFAULT_SONNET_MODEL</span>=<span class="string">&quot;deepseek-v4-pro[1m]&quot;</span></span><br><span class="line"><span class="variable">$env:ANTHROPIC_DEFAULT_HAIKU_MODEL</span>=<span class="string">&quot;deepseek-v4-flash&quot;</span></span><br><span class="line"><span class="variable">$env:CLAUDE_CODE_SUBAGENT_MODEL</span>=<span class="string">&quot;deepseek-v4-flash&quot;</span></span><br><span class="line"><span class="variable">$env:CLAUDE_CODE_EFFORT_LEVEL</span>=<span class="string">&quot;max&quot;</span></span><br></pre></td></tr></table></figure><h2 id="Emacs">Emacs</h2><p>Emacs is generally used in Linux environments; Windows Emacs has too many bugs, so the following configuration is all for the Linux environment. First, still install Claude Code, then set the environment variables.<code>$HOME/.bashrc</code>or<code>$HOME/.zshrc</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic</span><br><span class="line"><span class="built_in">export</span> ANTHROPIC_AUTH_TOKEN=&lt;你的 DeepSeek API Key&gt;</span><br><span class="line"><span class="built_in">export</span> ANTHROPIC_MODEL=deepseek-v4-pro[1m]</span><br><span class="line"><span class="built_in">export</span> ANTHROPIC_DEFAULT_OPUS_MODEL=deepseek-v4-pro[1m]</span><br><span class="line"><span class="built_in">export</span> ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek-v4-pro[1m]</span><br><span class="line"><span class="built_in">export</span> ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-flash</span><br><span class="line"><span class="built_in">export</span> CLAUDE_CODE_SUBAGENT_MODEL=deepseek-v4-flash</span><br><span class="line"><span class="built_in">export</span> CLAUDE_CODE_EFFORT_LEVEL=max</span><br></pre></td></tr></table></figure><p>Then enable the environment variables</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># bash</span></span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br><span class="line"><span class="comment"># zsh</span></span><br><span class="line"><span class="built_in">source</span> ~/.zshrc</span><br></pre></td></tr></table></figure><p>Mainly use the claude-code.el package:</p><div class="tag link"><a class="link-card" title="claude-code.el" href="https://github.com/stevemolitor/claude-code.el"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.png"/></div><div class="right"><p class="text">claude-code.el</p><p class="url">https://github.com/stevemolitor/claude-code.el</p></div></a></div><p>The configuration is as follows:</p><figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">;; claude code</span></span><br><span class="line"><span class="comment">;; install required inheritenv dependency:</span></span><br><span class="line">(<span class="name">use-package</span> inheritenv</span><br><span class="line">  <span class="symbol">:vc</span> (<span class="symbol">:url</span> <span class="string">&quot;https://github.com/purcell/inheritenv&quot;</span> <span class="symbol">:rev</span> <span class="symbol">:newest</span>))</span><br><span class="line"></span><br><span class="line">(<span class="name">use-package</span> monet</span><br><span class="line">  <span class="symbol">:vc</span> (<span class="symbol">:url</span> <span class="string">&quot;https://github.com/stevemolitor/monet&quot;</span> <span class="symbol">:rev</span> <span class="symbol">:newest</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment">;; for vterm terminal backend:</span></span><br><span class="line">(<span class="name">use-package</span> vterm <span class="symbol">:ensure</span> <span class="literal">t</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">;; install claude-code.el</span></span><br><span class="line">(<span class="name">use-package</span> claude-code <span class="symbol">:ensure</span> <span class="literal">t</span></span><br><span class="line">  <span class="symbol">:vc</span> (<span class="symbol">:url</span> <span class="string">&quot;https://github.com/stevemolitor/claude-code.el&quot;</span> <span class="symbol">:rev</span> <span class="symbol">:newest</span>)</span><br><span class="line">  <span class="symbol">:config</span></span><br><span class="line">  <span class="comment">;; optional IDE integration with Monet</span></span><br><span class="line">  (<span class="name">add-hook</span> &#x27;claude-code-process-environment-functions #&#x27;monet-start-server-function)</span><br><span class="line">  (<span class="name">monet-mode</span> <span class="number">1</span>)</span><br><span class="line">  (<span class="name">setq</span> claude-code-terminal-backend &#x27;vterm)</span><br><span class="line">  (<span class="name">claude-code-mode</span>)</span><br><span class="line">  <span class="symbol">:bind-keymap</span> (<span class="string">&quot;C-c c&quot;</span> . claude-code-command-map)</span><br><span class="line">  <span class="comment">;; Optionally define a repeat map so that &quot;M&quot; will cycle thru Claude auto-accept/plan/confirm modes after invoking claude-code-cycle-mode / C-c M.</span></span><br><span class="line">  <span class="symbol">:bind</span></span><br><span class="line">  (<span class="symbol">:repeat-map</span> my-claude-code-map (<span class="string">&quot;M&quot;</span> . claude-code-cycle-mode)))</span><br></pre></td></tr></table></figure><p>Enter<code>C-c c c</code>to start the Claude Code window. Other commands can be viewed via claude-code-transient (C-c c m).</p><h1 id="Skill">Skill</h1><p>Skill is an extension mechanism for Claude Code launched by Anthropic in October 2025. It can be understood as a skill pack for Claude Code, essentially a Markdown file.<code>SKILL.md</code>It contains the purpose, prompts, rules, and workflow of this Skill. Its storage location:</p><ul><li><strong>Project-level directory</strong>, which is under your project root directory<code>$&#123;workspaceFolder&#125;/.claude/skills/</code>Skills placed here only take effect in the current project, suitable for skills strongly tied to the project, such as project-specific code conventions, deployment processes, etc.</li><li><strong>User-level directory</strong>, which is the directory under your home folder<code>$HOME/.claude/skills/</code>Skills placed here are available in all projects, suitable for general skills unrelated to specific projects, such as making PPTs, writing documents, formatting WeChat public accounts, etc.</li></ul><blockquote><p>Another concept is MCP (Model Context Protocol). MCP is a standard protocol that allows AI assistants to safely interact with the external world. For example, enabling AI to read local files on your computer, operate GitHub repositories, query databases, send Slack messages, control browsers, etc.</p></blockquote><p>Install Skills as follows:</p><ol><li>Manual copy<code>SKILL.md</code>to the project-level directory or user-level directory</li><li>Install plugins</li></ol><p>Reference:</p><div class="tag link"><a class="link-card" title="Discover and install pre-built plugins through the marketplace" href="https://code.claude.com/docs/zh-CN/discover-plugins"><div class="left"><img loading="lazy" src="https://code.claude.com/docs/_mintlify/favicons/claude-code/pLsy-mRpNksna2sx/_generated/favicon/favicon.ico"/></div><div class="right"><p class="text">Discover and install pre-built plugins through the marketplace</p><p class="url">https://code.claude.com/docs/zh-CN/discover-plugins</p></div></a></div><p>The official Anthropic marketplace (claude-plugins-official) is automatically available when starting Claude Code. Run /plugin and go to the Discover tab to browse available content, or<code>claude.com/plugins</code>view the directory.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">/plugin install github@claude-plugins-official</span><br><span class="line"></span><br><span class="line"><span class="comment"># Afterwards, you can manage plugins via /plugin</span></span><br></pre></td></tr></table></figure><p>Recommended Skills to install<br>Karpathy-Inspired Claude Code Guidelines:</p><div class="tag link"><a class="link-card" title="Karpathy-Inspired Claude Code Guidelines" href="https://github.com/multica-ai/andrej-karpathy-skills"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">Karpathy-Inspired Claude Code Guidelines</p><p class="url">https://github.com/multica-ai/andrej-karpathy-skills</p></div></a></div><p>codegraph:</p><div class="tag link"><a class="link-card" title="codegraph" href="https://github.com/colbymchenry/codegraph"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">codegraph</p><p class="url">https://github.com/colbymchenry/codegraph</p></div></a></div><p>draw.io</p><div class="tag link"><a class="link-card" title="draw.io" href="https://github.com/jgraph/drawio-mcp/blob/main/plugins/claude-code/README.md"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">draw.io</p><p class="url">https://github.com/jgraph/drawio-mcp/blob/main/plugins/claude-code/README.md</p></div></a></div><h1 id="CC-Switch">CC-Switch</h1><p>A very useful AI aggregation tool that allows easy switching between different Agents and Models</p><div class="tag link"><a class="link-card" title="CC-Switch" href="https://github.com/farion1231/cc-switch"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">CC-Switch</p><p class="url">https://github.com/farion1231/cc-switch</p></div></a></div><blockquote><p>With CC-Switch, there’s no need to set environment variables</p></blockquote><h1 id="Reference">Reference</h1><div class="reference-source"><span class="hidden-anchor" id="referfrom_[1]"></span><a class="reference-anchor" href="#referto_[1]">[1]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Step-by-step tutorial！Hands-on guide toClaude Codeinstalling and using inSKILL" href="https://zhuanlan.zhihu.com/p/2032394693405885173">Step-by-step tutorial！Hands-on guide toClaude Codeinstalling and using inSKILL</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[2]"></span><a class="reference-anchor" href="#referto_[2]">[2]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="What experts are secretly using Claude Code Official plugin list" href="https://zhuanlan.zhihu.com/p/2016937425046353795">What experts are secretly using Claude Code Official plugin list</a></div>]]></content>
    
    
    <summary type="html">This article introduces the download, installation, and editor integration methods of Claude Code, detailing how to configure and use it with the DeepSeek API in VSCode and Emacs. Additionally, it discusses Claude Code&#39;s Skill extension mechanism, the MCP model context protocol, as well as the installation of related Skills and recommended plugins.</summary>
    
    
    
    <category term="tools" scheme="https://even629.com/en/categories/tools/"/>
    
    
    <category term="tools" scheme="https://even629.com/en/tags/tools/"/>
    
    <category term="AI" scheme="https://even629.com/en/tags/AI/"/>
    
  </entry>
  
  <entry>
    <title>smatch</title>
    <link href="https://even629.com/en/posts/202605211/"/>
    <id>https://even629.com/en/posts/202605211/</id>
    <published>2026-05-21T15:10:13.000Z</published>
    <updated>2026-05-21T15:10:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-05-21</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article introduces Smatch, a static analysis tool designed specifically for the Linux kernel, detailing its compilation method, database construction process, and its ability to discover hidden bugs through cross-file analysis. Additionally, it summarizes the specific steps for running Smatch to perform static analysis on kernel and non-kernel projects, along with the configuration methods for related script parameters.</blockquote><hr><p>Smatch is a static analysis tool designed specifically for the Linux kernel, capable of deeply tracing code execution paths to uncover deeply hidden bugs, such as null pointer dereferences, lock usage errors, resource leaks, etc. Reference documentation:</p><div class="tag link"><a class="link-card" title="smatch" href="https://github.com/error27/smatch/blob/master/Documentation/smatch.rst"><div class="left"><img loading="lazy" src="https://github.githubassets.com/favicons/favicon.svg"/></div><div class="right"><p class="text">smatch</p><p class="url">https://github.com/error27/smatch/blob/master/Documentation/smatch.rst</p></div></a></div><p>Compile Smatch</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Install Dependencies</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install sqlite3 libsqlite3-dev libdbd-sqlite3-perl</span><br><span class="line"><span class="comment"># Compile Smatch</span></span><br><span class="line"><span class="built_in">cd</span> ~/repository/linux/</span><br><span class="line">wget https://github.com/error27/smatch/archive/refs/tags/1.74.tar.gz -O smatch-1.74.tar.gz</span><br><span class="line"><span class="built_in">cd</span> smatch-1.74</span><br><span class="line">make -j$(<span class="built_in">nproc</span>)</span><br></pre></td></tr></table></figure><h2 id="kernel">kernel</h2><p>Smatch essentially follows the kernel build system, so it must be able to correctly locate the compiler and header files. Therefore, if cross-compilation is needed, environment variables must be set first.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> ARCH=arm64</span><br><span class="line"><span class="built_in">export</span> CROSS_COMPILE=aarch64-none-linux-gnu-</span><br></pre></td></tr></table></figure><p>Analyze and Build Database</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/repository/linux/linux-5.10.256</span><br><span class="line"></span><br><span class="line"><span class="comment"># Compile Linux</span></span><br><span class="line">make defconfig</span><br><span class="line">make -j$(<span class="built_in">nproc</span>) Image</span><br><span class="line"></span><br><span class="line"><span class="comment"># Static Analysis and Database Construction</span></span><br><span class="line">~/repository/linux/smatch-1.74/smatch_scripts/build_kernel_data.sh</span><br></pre></td></tr></table></figure><p><code>build_kernel_data.sh</code>will append<code>--call-tree</code>, <code>--info</code>, <code>--spammy</code>, <code>--data=$DATA_DIR</code>parameter call<code>smatch_scripts/test_kernel.sh</code>, then call<code>smatch_data/db/create_db.sh</code>build Smatch database</p><blockquote><p>Smatch does not require building a database, but building one makes it more powerful. Once the database is built, the next time you compile, Smatch can look up information such as ‘how many times the printk function is called throughout the kernel’ or ‘whether a certain struct pointer has been freed in other C files,’ enabling epic cross-file vulnerability detection.</p></blockquote><p>Run smatch for static analysis of the kernel: Run smatch to check the entire kernel</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~/repository/linux/smatch-1.74/smatch_scripts/test_kernel.sh --data=<span class="string">&quot;<span class="variable">$HOME</span>/repository/linux/smatch-1.74/smatch_data&quot;</span></span><br></pre></td></tr></table></figure><p>Script parameters</p><ul><li><code>--endian</code>: Enable big/little endian byte order checking.</li><li><code>--target &quot;bzImage&quot;</code>: Specify the build target (default is bzImage modules).</li><li><code>--log smatch_compile.warns</code>: Specify the build log output file</li><li><code>--wlog smatch_warns.txt</code>: Customize the output file name for Smatch warnings.</li></ul><p>After compilation, two files will be generated in the current directory:</p><ul><li><code>smatch_compile.warns</code>: Complete kernel build log (including errors and warnings).</li><li><code>smatch_warns.txt</code>: Pure Smatch static check warning messages.</li></ul><p>You can also check code under a specific file or folder</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~/repository/linux/smatch-1.74/smatch_scripts/kchecker drivers/rpmsg/rpmsg_core.c</span><br><span class="line">~/repository/linux/smatch-1.74/smatch_scripts/kchecker drivers/rpmsg/</span><br></pre></td></tr></table></figure><p>The smatch author recommends frequently updating the smatch database, as each update makes cross-function checks more accurate</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~/repository/linux/smatch-1.74/smatch_data/db/create_db.sh -p=kernel smatch_warns.txt</span><br></pre></td></tr></table></figure><p>When running, smatch reads some rules set in smatch_data, in<code>~/repository/linux/smatch-1.74/smatch.c</code>middle<code>static char *get_data_dir(char *arg0)</code>there is related logic: you can pass<code>--data=/path/to/smatch_data</code>Specify</p><h2 id="out-of-tree-module">out-of-tree module</h2><p>For non-kernel projects, use the following method to build the database and analyze</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> ARCH=arm64</span><br><span class="line"><span class="built_in">export</span> CROSS_COMPILE=aarch64-none-linux-gnu-</span><br><span class="line"></span><br><span class="line">make -C ~/repository/linux/linux-5.10.256 \</span><br><span class="line">     M=<span class="variable">$PWD</span> \</span><br><span class="line">     -j$(<span class="built_in">nproc</span>) \</span><br><span class="line">     CHECK=<span class="string">&quot;<span class="variable">$HOME</span>/repository/linux/smatch-1.74/smatch -p=kernel --file-output --succeed --call-tree --info --spammy --data=<span class="variable">$HOME</span>/repository/linux/smatch-1.74/smatch_data&quot;</span> \</span><br><span class="line">     C=2</span><br><span class="line"></span><br><span class="line">~/repository/linux/smatch-1.74/smatch_data/db/create_db.sh -p=kernel hello_world.c.smatch</span><br><span class="line"></span><br><span class="line">make -C ~/repository/linux/linux-5.10.256 \</span><br><span class="line">     M=<span class="variable">$PWD</span> \</span><br><span class="line">     -j$(<span class="built_in">nproc</span>) \</span><br><span class="line">     CHECK=<span class="string">&quot;<span class="variable">$HOME</span>/repository/linux/smatch-1.74/smatch -p=kernel --succeed --data=<span class="variable">$HOME</span>/repository/linux/smatch-1.74/smatch_data&quot;</span> \</span><br><span class="line">     C=2</span><br></pre></td></tr></table></figure><ul><li><code>--file-output</code>Output one result per file</li><li><code>--succeed</code>Indicates to continue analysis even if errors occur</li><li><code>--call-tree</code>Indicates enabling cross-function call analysis</li><li><code>--info</code>Indicates more detailed analysis logs</li><li><code>--spammy</code>Indicates more aggressive checking</li></ul><blockquote><p>When the --file-output parameter is used, smatch will not print warnings directly to the terminal’s stdout/stderr by default, but will instead generate a bunch of hidden text files in the same directory as your code:</p><ul><li><code>.hello_world.c.smatch</code>(General warnings)</li><li><code>.hello_world.c.smatch.caller_info</code>(If you added parameters like --info)</li></ul></blockquote><h2 id="References">References</h2><div class="reference-source"><span class="hidden-anchor" id="referfrom_[1]"></span><a class="reference-anchor" href="#referto_[1]">[1]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Automatic detection Linux Wrong tool - Static section" href="https://zhuanlan.zhihu.com/p/641596339">Automatic detection Linux Wrong tool - Static section</a></div><div class="reference-source"><span class="hidden-anchor" id="referfrom_[2]"></span><a class="reference-anchor" href="#referto_[2]">[2]<div class="reference-anchor-up fa-solid fa-angles-up"></div></a><a class="reference-link" title="Kernel Testing Guide" href="https://docs.kernel.org/dev-tools/testing-overview.html">Kernel Testing Guide</a></div>]]></content>
    
    
    <summary type="html">This article introduces Smatch, a static analysis tool designed specifically for the Linux kernel, detailing its compilation method, database construction process, and its ability to discover hidden bugs through cross-file analysis. Additionally, it summarizes the specific steps for running Smatch to perform static analysis on kernel and non-kernel projects, along with the configuration methods for related script parameters.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>Query the earliest version where a kernel API was introduced</title>
    <link href="https://even629.com/en/posts/202605210/"/>
    <id>https://even629.com/en/posts/202605210/</id>
    <published>2026-05-21T15:08:13.000Z</published>
    <updated>2026-05-21T15:08:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-05-21</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>This article describes how to query the earliest version where a specific kernel API was introduced, and illustrates the query method with concrete examples.</blockquote><hr><p>How to check which version introduced a certain kernel API? Take<code>array_index_nospec</code>as an example</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/torvalds/linux.git</span><br><span class="line"></span><br><span class="line"><span class="comment"># Find its definition in include/linux/nospec</span></span><br><span class="line">git blame include/linux/nospec.h</span><br><span class="line"></span><br><span class="line"><span class="comment"># Find the commit ID</span></span><br><span class="line">git show f3804203306e0</span><br><span class="line"></span><br><span class="line"><span class="comment"># Check all tags containing this commit ID</span></span><br><span class="line">git tag --contains f3804203306e0</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">This article describes how to query the earliest version where a specific kernel API was introduced, and illustrates the query method with concrete examples.</summary>
    
    
    
    <category term="Linux" scheme="https://even629.com/en/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://even629.com/en/tags/Linux/"/>
    
    <category term="GNU" scheme="https://even629.com/en/tags/GNU/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Daily Problem P3546 Equal Sum Matrix Partition I</title>
    <link href="https://even629.com/en/posts/3546/"/>
    <id>https://even629.com/en/posts/3546/</id>
    <published>2026-03-25T02:28:13.000Z</published>
    <updated>2026-03-25T02:28:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-25</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Prefix sum</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P3546 Equal sum matrix partition I" href="https://leetcode.cn/problems/equal-sum-grid-partition-i/description/?envType=daily-question&envId=2026-03-25"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P3546 Equal sum matrix partition I</p><p class="url">https://leetcode.cn/problems/equal-sum-grid-partition-i/description/?envType=daily-question&envId=2026-03-25</p></div></a></div><p>A reskinned prefix sum problem, note that addition may exceed the maximum value representable by int</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        <span class="function"><span class="type">bool</span> <span class="title">canPartitionGrid</span><span class="params">(vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; &amp;grid)</span></span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">                <span class="comment">// 1 &lt;= m == grid.length &lt;= 105</span></span><br><span class="line">                <span class="comment">// 1 &lt;= n == grid[i].length &lt;= 105</span></span><br><span class="line">                <span class="comment">// 2 &lt;= m * n &lt;= 105</span></span><br><span class="line">                <span class="comment">// 1 &lt;= grid[i][j] &lt;= 105</span></span><br><span class="line">                <span class="type">int</span> i, j, m = grid.<span class="built_in">size</span>(), n = grid[<span class="number">0</span>].<span class="built_in">size</span>();</span><br><span class="line">                <span class="type">int</span> total = m * n;</span><br><span class="line">                <span class="type">long</span> last;</span><br><span class="line">                <span class="function">vector&lt;<span class="type">long</span>&gt; <span class="title">prefix_sum</span><span class="params">(total, <span class="number">0</span>)</span></span>;</span><br><span class="line">                <span class="function">vector&lt;<span class="type">long</span>&gt; <span class="title">suffix_sum</span><span class="params">(total, <span class="number">0</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">                <span class="comment">// Horizontal partition</span></span><br><span class="line">                last = grid[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; m; i++) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; n; j++) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (i == <span class="number">0</span> &amp;&amp; j == <span class="number">0</span>)</span><br><span class="line">                                        <span class="keyword">continue</span>;</span><br><span class="line">                                prefix_sum[i * n + j] = last + prefix_sum[i * n + j - <span class="number">1</span>];</span><br><span class="line">                                last = grid[i][j];</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                last = grid[m - <span class="number">1</span>][n - <span class="number">1</span>];</span><br><span class="line">                <span class="keyword">for</span> (i = m - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = n - <span class="number">1</span>; j &gt;= <span class="number">0</span>; j--) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (i == m - <span class="number">1</span> &amp;&amp; j == n - <span class="number">1</span>)</span><br><span class="line">                                        <span class="keyword">continue</span>;</span><br><span class="line">                                suffix_sum[i * n + j] = last + suffix_sum[i * n + j + <span class="number">1</span>];</span><br><span class="line">                                last = grid[i][j];</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; m - <span class="number">1</span>; i++) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (prefix_sum[i * n + n - <span class="number">1</span>] + grid[i][n - <span class="number">1</span>] == suffix_sum[i * n + n - <span class="number">1</span>])</span><br><span class="line">                                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">// Vertical partition</span></span><br><span class="line">                prefix_sum[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line">                last = grid[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line">                <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; n; j++) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; m; i++) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (i == <span class="number">0</span> &amp;&amp; j == <span class="number">0</span>)</span><br><span class="line">                                        <span class="keyword">continue</span>;</span><br><span class="line">                                prefix_sum[j * m + i] = last + prefix_sum[j * m + i - <span class="number">1</span>];</span><br><span class="line">                                last = grid[i][j];</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                suffix_sum[total - <span class="number">1</span>] = <span class="number">0</span>;</span><br><span class="line">                last = grid[m - <span class="number">1</span>][n - <span class="number">1</span>];</span><br><span class="line">                <span class="keyword">for</span> (j = n - <span class="number">1</span>; j &gt;= <span class="number">0</span>; j--) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (i = m - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (i == m - <span class="number">1</span> &amp;&amp; j == n - <span class="number">1</span>)</span><br><span class="line">                                        <span class="keyword">continue</span>;</span><br><span class="line">                                suffix_sum[j * m + i] = last + suffix_sum[j * m + i + <span class="number">1</span>];</span><br><span class="line">                                last = grid[i][j];</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">for</span> (j = <span class="number">1</span>; j &lt; n; j++) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (prefix_sum[j * m] == suffix_sum[j * m] + grid[<span class="number">0</span>][j])</span><br><span class="line">                                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Prefix sum</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="leetcode Daily Problem" scheme="https://even629.com/en/tags/leetcode-Daily-Problem/"/>
    
    <category term="Prefix Sum" scheme="https://even629.com/en/tags/Prefix-Sum/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Daily Problem P2906 Construct Product Matrix</title>
    <link href="https://even629.com/en/posts/2906/"/>
    <id>https://even629.com/en/posts/2906/</id>
    <published>2026-03-24T09:01:13.000Z</published>
    <updated>2026-03-24T09:01:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-24</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Prefix sum</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P2906 Construct product matrix" href="https://leetcode.cn/problems/construct-product-matrix/description/?envType=daily-question&envId=2026-03-24"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P2906 Construct product matrix</p><p class="url">https://leetcode.cn/problems/construct-product-matrix/description/?envType=daily-question&envId=2026-03-24</p></div></a></div><p>A variant of the prefix sum problem, note that the product might exceed the maximum value representable by int</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MODULO_NUM 12345</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; <span class="built_in">constructProductMatrix</span>(vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; &amp;grid)</span><br><span class="line">        &#123;</span><br><span class="line">                <span class="comment">// 1 &lt;= n == grid.length &lt;= 105</span></span><br><span class="line">                <span class="comment">// 1 &lt;= m == grid[i].length &lt;= 105</span></span><br><span class="line">                <span class="comment">// 2 &lt;= n * m &lt;= 105</span></span><br><span class="line">                <span class="comment">// 1 &lt;= grid[i][j] &lt;= 109</span></span><br><span class="line">                <span class="type">int</span> i, j, m = grid.<span class="built_in">size</span>(), n = grid[<span class="number">0</span>].<span class="built_in">size</span>();</span><br><span class="line">                <span class="type">int</span> total = m * n, last;</span><br><span class="line">                vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; <span class="built_in">product_matrix</span>(m, (<span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(n, <span class="number">0</span>)));</span><br><span class="line">                <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">prefix_product</span><span class="params">(total, <span class="number">1</span>)</span></span>;</span><br><span class="line">                <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">suffix_product</span><span class="params">(total, <span class="number">1</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">                <span class="comment">// prefix</span></span><br><span class="line">                last = grid[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; m; i++) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; n; j++) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (i == <span class="number">0</span> &amp;&amp; j == <span class="number">0</span>)</span><br><span class="line">                                        <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">                                prefix_product[i * n + j] =</span><br><span class="line">                                        (<span class="type">long</span>)((<span class="type">long</span>)last * (<span class="type">long</span>)prefix_product[i * n + j - <span class="number">1</span>]) %</span><br><span class="line">                                        MODULO_NUM;</span><br><span class="line">                                last = grid[i][j];</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// suffix</span></span><br><span class="line">                last = grid[m - <span class="number">1</span>][n - <span class="number">1</span>];</span><br><span class="line">                <span class="keyword">for</span> (i = m - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = n - <span class="number">1</span>; j &gt;= <span class="number">0</span>; j--) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (i == m - <span class="number">1</span> &amp;&amp; j == n - <span class="number">1</span>)</span><br><span class="line">                                        <span class="keyword">continue</span>;</span><br><span class="line">                                suffix_product[i * n + j] =</span><br><span class="line">                                        (<span class="type">long</span>)((<span class="type">long</span>)last * (<span class="type">long</span>)suffix_product[i * n + j + <span class="number">1</span>]) %</span><br><span class="line">                                        MODULO_NUM;</span><br><span class="line">                                last = grid[i][j];</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; m; i++) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; n; j++) &#123;</span><br><span class="line">                                product_matrix[i][j] = (<span class="type">long</span>)((<span class="type">long</span>)prefix_product[i * n + j] *</span><br><span class="line">                                                              (<span class="type">long</span>)suffix_product[i * n + j]) %</span><br><span class="line">                                                       MODULO_NUM;</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> product_matrix;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Prefix sum</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="leetcode Daily Problem" scheme="https://even629.com/en/tags/leetcode-Daily-Problem/"/>
    
    <category term="Prefix Sum" scheme="https://even629.com/en/tags/Prefix-Sum/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Top 100 P1143 Longest Common Subsequence</title>
    <link href="https://even629.com/en/posts/1143/"/>
    <id>https://even629.com/en/posts/1143/</id>
    <published>2026-03-21T09:09:13.000Z</published>
    <updated>2026-03-21T09:09:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-21</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Dynamic Programming</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P1143 Longest Common Subsequence" href="https://leetcode.cn/problems/longest-common-subsequence/description/?envType=study-plan-v2&envId=top-100-liked"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P1143 Longest Common Subsequence</p><p class="url">https://leetcode.cn/problems/longest-common-subsequence/description/?envType=study-plan-v2&envId=top-100-liked</p></div></a></div><p>It’s a classic problem,<code>dp[i][j]</code> represents <code>text1[0..=i]</code> and <code>text2[0..=j]</code> 's longest common subsequence length, the state transition equation is</p><ul><li>When <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi><mi>e</mi><mi>x</mi><mi>t</mi><mn>1</mn><mo stretchy="false">[</mo><mi>i</mi><mo stretchy="false">]</mo><mo>=</mo><mo>=</mo><mi>t</mi><mi>e</mi><mi>x</mi><mi>t</mi><mn>2</mn><mo stretchy="false">[</mo><mi>j</mi><mo stretchy="false">]</mo></mrow><annotation encoding="application/x-tex"> text1[i] == text2[j] </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">t</span><span class="mord">1</span><span class="mopen">[</span><span class="mord mathnormal">i</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">==</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">t</span><span class="mord">2</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mclose">]</span></span></span></span>:<ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mi>p</mi><mo stretchy="false">[</mo><mi>i</mi><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mi>j</mi><mo stretchy="false">]</mo><mo>=</mo><mi>d</mi><mi>p</mi><mo stretchy="false">[</mo><mi>i</mi><mo>−</mo><mn>1</mn><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mi>j</mi><mo>−</mo><mn>1</mn><mo stretchy="false">]</mo><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex"> dp[i][j] = dp[i-1][j-1] + 1 </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">p</span><span class="mopen">[</span><span class="mord mathnormal">i</span><span class="mclose">]</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">p</span><span class="mopen">[</span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">]</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span></li></ul></li><li>otherwise:<ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mi>p</mi><mo stretchy="false">[</mo><mi>i</mi><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mi>j</mi><mo stretchy="false">]</mo><mo>=</mo><mi>m</mi><mi>a</mi><mi>x</mi><mo stretchy="false">(</mo><mi>d</mi><mi>p</mi><mo stretchy="false">[</mo><mi>i</mi><mo>−</mo><mn>1</mn><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mi>j</mi><mo stretchy="false">]</mo><mo separator="true">,</mo><mi>d</mi><mi>p</mi><mo stretchy="false">[</mo><mi>i</mi><mo stretchy="false">]</mo><mo stretchy="false">[</mo><mi>j</mi><mo>−</mo><mn>1</mn><mo stretchy="false">]</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex"> dp[i][j] = max(dp[i-1][j], dp[i][j-1]) </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">p</span><span class="mopen">[</span><span class="mord mathnormal">i</span><span class="mclose">]</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">ma</span><span class="mord mathnormal">x</span><span class="mopen">(</span><span class="mord mathnormal">d</span><span class="mord mathnormal">p</span><span class="mopen">[</span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">]</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mclose">]</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">p</span><span class="mopen">[</span><span class="mord mathnormal">i</span><span class="mclose">]</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.05724em;">j</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">])</span></span></span></span></li></ul></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> std::string;</span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        <span class="function"><span class="type">int</span> <span class="title">longestCommonSubsequence</span><span class="params">(string text1, string text2)</span></span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">                <span class="type">int</span> i, j, n1 = text<span class="number">1.</span><span class="built_in">size</span>(), n2 = text<span class="number">2.</span><span class="built_in">size</span>();</span><br><span class="line">                vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; <span class="built_in">dp</span>(n1, <span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(n2, <span class="number">0</span>));</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; n1; i++) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (text1[i] == text2[<span class="number">0</span>]) &#123;</span><br><span class="line">                                <span class="keyword">while</span> (i &lt; n1)</span><br><span class="line">                                        dp[i++][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line">                                <span class="keyword">break</span>;</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; n2; j++) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (text2[j] == text1[<span class="number">0</span>]) &#123;</span><br><span class="line">                                <span class="keyword">while</span> (j &lt; n2)</span><br><span class="line">                                        dp[<span class="number">0</span>][j++] = <span class="number">1</span>;</span><br><span class="line">                                <span class="keyword">break</span>;</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">// dp[i][j] represents the longest common subsequence length of text1[0..=i] and text2[0..=j]</span></span><br><span class="line"></span><br><span class="line">                <span class="comment">// dp[i][j] = dp[i-1][j-1] + 1 (text1[i] == text2[j])</span></span><br><span class="line">                <span class="comment">// dp[i][j] = max(dp[i-1][j], dp[i][j-1])</span></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt; n1; i++) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = <span class="number">1</span>; j &lt; n2; j++) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (text1[i] == text2[j])</span><br><span class="line">                                        dp[i][j] = dp[i - <span class="number">1</span>][j - <span class="number">1</span>] + <span class="number">1</span>;</span><br><span class="line">                                <span class="keyword">else</span></span><br><span class="line">                                        dp[i][j] = std::<span class="built_in">max</span>(dp[i - <span class="number">1</span>][j], dp[i][j - <span class="number">1</span>]);</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> dp[n1 - <span class="number">1</span>][n2 - <span class="number">1</span>];</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Dynamic Programming</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="Dynamic Programming" scheme="https://even629.com/en/tags/Dynamic-Programming/"/>
    
    <category term="leetcode Hot 100" scheme="https://even629.com/en/tags/leetcode-Hot-100/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Hot 100 P62 Unique Paths</title>
    <link href="https://even629.com/en/posts/62/"/>
    <id>https://even629.com/en/posts/62/</id>
    <published>2026-03-21T07:15:13.000Z</published>
    <updated>2026-03-21T07:15:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-21</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Dynamic Programming</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P62 Unique Paths" href="https://leetcode.cn/problems/unique-paths/description/?envType=study-plan-v2&envId=top-100-liked"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P62 Unique Paths</p><p class="url">https://leetcode.cn/problems/unique-paths/description/?envType=study-plan-v2&envId=top-100-liked</p></div></a></div><p>Dynamic Programming</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        <span class="function"><span class="type">int</span> <span class="title">uniquePaths</span><span class="params">(<span class="type">int</span> m, <span class="type">int</span> n)</span></span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">                <span class="type">int</span> i, j;</span><br><span class="line">                vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; <span class="built_in">dp</span>(m, <span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(n, <span class="number">0</span>));</span><br><span class="line">                <span class="comment">// dp[i][j] represents the total number of unique paths to (i,j)</span></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; m; i++)</span><br><span class="line">                        dp[i][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; n; j++)</span><br><span class="line">                        dp[<span class="number">0</span>][j] = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt; m; i++) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = <span class="number">1</span>; j &lt; n; j++)</span><br><span class="line">                                dp[i][j] = dp[i - <span class="number">1</span>][j] + dp[i][j - <span class="number">1</span>];</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> dp[m - <span class="number">1</span>][n - <span class="number">1</span>];</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Dynamic Programming</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="Dynamic Programming" scheme="https://even629.com/en/tags/Dynamic-Programming/"/>
    
    <category term="leetcode Hot 100" scheme="https://even629.com/en/tags/leetcode-Hot-100/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Top 100 P32 Longest Valid Parentheses</title>
    <link href="https://even629.com/en/posts/32/"/>
    <id>https://even629.com/en/posts/32/</id>
    <published>2026-03-21T06:22:13.000Z</published>
    <updated>2026-03-21T06:22:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-21</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Dynamic Programming, Stack</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P416 Partition Equal Subset Sum" href="https://leetcode.cn/problems/longest-valid-parentheses/description/?envType=study-plan-v2&envId=top-100-liked"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P416 Partition Equal Subset Sum</p><p class="url">https://leetcode.cn/problems/longest-valid-parentheses/description/?envType=study-plan-v2&envId=top-100-liked</p></div></a></div><ul><li>Simulate with a stack, set all positions of unmatched parentheses to 1,<ul><li>For example: <code>()(()</code> the mark is [0, 0, 1, 0, 0]</li><li>Another example: <code>)()((())</code> the mark is [1, 0, 0, 1, 0, 0, 0, 0]</li></ul></li><li>After such processing, this problem becomes<strong>finding the length of the longest consecutive 0s</strong></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stack&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> std::string;</span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"><span class="keyword">using</span> std::stack;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        <span class="function"><span class="type">int</span> <span class="title">longestValidParentheses</span><span class="params">(string s)</span></span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">                <span class="type">int</span> i, j, n = s.<span class="built_in">size</span>();</span><br><span class="line">                <span class="type">int</span> max_len = <span class="number">0</span>;</span><br><span class="line">                stack&lt;<span class="type">int</span>&gt; stk;</span><br><span class="line">                <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">arr</span><span class="params">(n, <span class="number">0</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (s[i] == <span class="string">&#x27;(&#x27;</span>) &#123;</span><br><span class="line">                                stk.<span class="built_in">push</span>(i);</span><br><span class="line">                        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                                <span class="keyword">if</span> (stk.<span class="built_in">empty</span>())</span><br><span class="line">                                        arr[i] = <span class="number">1</span>;</span><br><span class="line">                                <span class="keyword">else</span></span><br><span class="line">                                        stk.<span class="built_in">pop</span>();</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">while</span> (!stk.<span class="built_in">empty</span>()) &#123; <span class="comment">//Unmatched parentheses</span></span><br><span class="line">                        arr[stk.<span class="built_in">top</span>()] = <span class="number">1</span>;</span><br><span class="line">                        stk.<span class="built_in">pop</span>();</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// Find the longest consecutive 0s</span></span><br><span class="line">                i = <span class="number">0</span>;</span><br><span class="line">                <span class="keyword">while</span> (i &lt; n) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (arr[i] == <span class="number">0</span>) &#123;</span><br><span class="line">                                j = i;</span><br><span class="line"></span><br><span class="line">                                <span class="keyword">while</span> (j &lt; n &amp;&amp; arr[j] == <span class="number">0</span>)</span><br><span class="line">                                        j++;</span><br><span class="line"></span><br><span class="line">                                max_len = std::<span class="built_in">max</span>(max_len, j - i);</span><br><span class="line">                                i = j + <span class="number">1</span>;</span><br><span class="line">                        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                                i++;</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> max_len;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Dynamic Programming, Stack</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="Dynamic Programming" scheme="https://even629.com/en/tags/Dynamic-Programming/"/>
    
    <category term="Stack" scheme="https://even629.com/en/tags/Stack/"/>
    
    <category term="leetcode Hot 100" scheme="https://even629.com/en/tags/leetcode-Hot-100/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Top 100 P416 Partition Equal Subset Sum</title>
    <link href="https://even629.com/en/posts/416/"/>
    <id>https://even629.com/en/posts/416/</id>
    <published>2026-03-21T04:06:13.000Z</published>
    <updated>2026-03-21T04:06:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-21</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Dynamic Programming</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P416 Partition Equal Subset Sum" href="https://leetcode.cn/problems/partition-equal-subset-sum/?envType=study-plan-v2&envId=top-100-liked"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P416 Partition Equal Subset Sum</p><p class="url">https://leetcode.cn/problems/partition-equal-subset-sum/?envType=study-plan-v2&envId=top-100-liked</p></div></a></div><p>Sum the array, then divide the sum by 2, transforming the problem into finding a subset of the array that equals half of the total sum, which is the 0-1 knapsack problem</p><p>dp[i][j] represents whether there exists a selection of some positive integers (can be 0) from the index range [0, i] of the array such that the sum of the selected positive integers equals j. Initially, all elements in dp are false.</p><p>Initialization:</p><ul><li>If no positive integers are selected, the sum of the selected positive integers equals 0. Therefore, for all 0 ≤ i &lt; n, dp[i][0] = true.</li><li>When i == 0, only one positive integer nums[0] can be selected, so dp[0][nums[0]] = true.</li></ul><p>State transition:</p><ul><li><code>dp[i][j] = dp[i−1][j] ∣ dp[i−1][j−nums[i]]</code> (j &gt;= nums[i])</li><li><code>dp[i][j] = dp[i-1][j]</code> (j &lt; nums[i])</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        <span class="function"><span class="type">bool</span> <span class="title">canPartition</span><span class="params">(vector&lt;<span class="type">int</span>&gt; &amp;nums)</span></span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">                <span class="type">int</span> i, j, n = nums.<span class="built_in">size</span>();</span><br><span class="line">                <span class="type">int</span> sum = <span class="number">0</span>, target;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; n; i++)</span><br><span class="line">                        sum += nums[i];</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (sum % <span class="number">2</span> != <span class="number">0</span>) <span class="comment">// Odd number</span></span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">                target = sum / <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; n; i++) &#123; <span class="comment">// There is a number exceeding half of the total sum</span></span><br><span class="line">                        <span class="keyword">if</span> (nums[<span class="number">0</span>] &gt; target)</span><br><span class="line">                                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 0-1 Knapsack Problem</span></span><br><span class="line">                <span class="comment">// dp[i][j] indicates whether it is possible to select some positive integers (can be 0) from the index range [0, i] of the array</span></span><br><span class="line">                <span class="comment">// such that the sum of the selected positive integers equals j. Initially, all elements in dp are false.</span></span><br><span class="line">                vector&lt;vector&lt;<span class="type">bool</span>&gt; &gt; <span class="built_in">dp</span>(n, <span class="built_in">vector</span>&lt;<span class="type">bool</span>&gt;(target + <span class="number">1</span>, <span class="literal">false</span>));</span><br><span class="line"></span><br><span class="line">                <span class="comment">// If no positive integers are selected, the sum of the selected positive integers equals 0. Therefore, for all 0 ≤ i &lt; n, dp[i][0] = true.</span></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; n; i++)</span><br><span class="line">                        dp[i][<span class="number">0</span>] = <span class="literal">true</span>;</span><br><span class="line">                <span class="comment">// When i == 0, only one positive integer nums[0] can be selected, so dp[0][nums[0]] = true.</span></span><br><span class="line">                dp[<span class="number">0</span>][nums[<span class="number">0</span>]] = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">                <span class="comment">// dp[i][j] = dp[i−1][j] ∣ dp[i−1][j−nums[i]] (j &gt;= nums[i])</span></span><br><span class="line">                <span class="comment">// dp[i][j] = dp[i-1][j] (j &lt; nums[i])</span></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt; n; i++) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = <span class="number">1</span>; j &lt;= target; j++) &#123;</span><br><span class="line">                                <span class="keyword">if</span> (j &gt;= nums[i])</span><br><span class="line">                                        dp[i][j] = dp[i - <span class="number">1</span>][j] | dp[i - <span class="number">1</span>][j - nums[i]];</span><br><span class="line">                                <span class="keyword">else</span></span><br><span class="line">                                        dp[i][j] = dp[i - <span class="number">1</span>][j];</span><br><span class="line">                        &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> dp[n - <span class="number">1</span>][target];</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Dynamic Programming</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="Dynamic Programming" scheme="https://even629.com/en/tags/Dynamic-Programming/"/>
    
    <category term="leetcode Hot 100" scheme="https://even629.com/en/tags/leetcode-Hot-100/"/>
    
    <category term="0-1 Knapsack Problem" scheme="https://even629.com/en/tags/0-1-Knapsack-Problem/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Hot 100 P152 Maximum Product Subarray</title>
    <link href="https://even629.com/en/posts/152/"/>
    <id>https://even629.com/en/posts/152/</id>
    <published>2026-03-21T02:44:13.000Z</published>
    <updated>2026-03-21T02:44:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-21</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Dynamic Programming</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P152 Maximum Product Subarray" href="https://leetcode.cn/problems/maximum-product-subarray/description/?envType=study-plan-v2&envId=top-100-liked"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P152 Maximum Product Subarray</p><p class="url">https://leetcode.cn/problems/maximum-product-subarray/description/?envType=study-plan-v2&envId=top-100-liked</p></div></a></div><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;algorithm&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        <span class="function"><span class="type">int</span> <span class="title">maxProduct</span><span class="params">(vector&lt;<span class="type">int</span>&gt; &amp;nums)</span></span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">                <span class="type">int</span> i, n = nums.<span class="built_in">size</span>();</span><br><span class="line">                <span class="type">int</span> max_val = nums[<span class="number">0</span>];</span><br><span class="line">                <span class="comment">// dp[i][0] represents the non-empty contiguous subarray ending at nums[i] with the maximum product</span></span><br><span class="line">                <span class="comment">// dp[i][1] represents the non-empty contiguous subarray ending at nums[i] with the minimum product</span></span><br><span class="line">                <span class="comment">// dp[i][0] = max&#123; dp[i-1][0] * nums[i],dp[i-1][1] *nums[i] , nums[i]&#125;</span></span><br><span class="line">                <span class="comment">// dp[i][1] = min&#123; dp[i-1][0] * nums[i],dp[i-1][1] *nums[i] , nums[i]&#125;</span></span><br><span class="line"></span><br><span class="line">                vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; <span class="built_in">dp</span>(n, <span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(<span class="number">2</span>));</span><br><span class="line"></span><br><span class="line">                dp[<span class="number">0</span>][<span class="number">0</span>] = nums[<span class="number">0</span>];</span><br><span class="line">                dp[<span class="number">0</span>][<span class="number">1</span>] = nums[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt; n; i++) &#123;</span><br><span class="line">                        dp[i][<span class="number">0</span>] = std::<span class="built_in">max</span>(</span><br><span class="line">                                &#123; dp[i - <span class="number">1</span>][<span class="number">0</span>] * nums[i], dp[i - <span class="number">1</span>][<span class="number">1</span>] * nums[i], nums[i] &#125;);</span><br><span class="line">                        dp[i][<span class="number">1</span>] = std::<span class="built_in">min</span>(</span><br><span class="line">                                &#123; dp[i - <span class="number">1</span>][<span class="number">0</span>] * nums[i], dp[i - <span class="number">1</span>][<span class="number">1</span>] * nums[i], nums[i] &#125;);</span><br><span class="line">                        max_val = std::<span class="built_in">max</span>(max_val, dp[i][<span class="number">0</span>]);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> max_val;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Dynamic Programming</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="Dynamic Programming" scheme="https://even629.com/en/tags/Dynamic-Programming/"/>
    
    <category term="leetcode Hot 100" scheme="https://even629.com/en/tags/leetcode-Hot-100/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Top 100 P279 Perfect Squares</title>
    <link href="https://even629.com/en/posts/279/"/>
    <id>https://even629.com/en/posts/279/</id>
    <published>2026-03-20T13:17:13.000Z</published>
    <updated>2026-03-20T13:17:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-20</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Dynamic Programming</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P279 Perfect Squares" href="https://leetcode.cn/problems/perfect-squares/description/?envType=study-plan-v2&envId=top-100-liked"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P279 Perfect Squares</p><p class="url">https://leetcode.cn/problems/perfect-squares/description/?envType=study-plan-v2&envId=top-100-liked</p></div></a></div><p>Dynamic Programming</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        <span class="function"><span class="type">int</span> <span class="title">numSquares</span><span class="params">(<span class="type">int</span> n)</span> <span class="comment">// 12</span></span></span><br><span class="line"><span class="function">        </span>&#123;</span><br><span class="line">                <span class="type">int</span> i, j;</span><br><span class="line">                vector&lt;<span class="type">int</span>&gt; perfect_squares;</span><br><span class="line">                <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">dp</span><span class="params">(n + <span class="number">1</span>, n + <span class="number">1</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">1</span>; i * i &lt;= n; i++)</span><br><span class="line">                        perfect_squares.<span class="built_in">push_back</span>(i * i); <span class="comment">// 1 4 9</span></span><br><span class="line"></span><br><span class="line">                dp[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt;= n; i++) &#123;</span><br><span class="line">                        <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; perfect_squares.<span class="built_in">size</span>() &amp;&amp; perfect_squares[j] &lt;= i; j++)</span><br><span class="line">                                dp[i] = std::<span class="built_in">min</span>(dp[i], dp[i - perfect_squares[j]] + <span class="number">1</span>);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> dp[n];</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cstdio&gt;</span></span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        Solution S;</span><br><span class="line">        <span class="type">int</span> num = S.<span class="built_in">numSquares</span>(<span class="number">12</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%d\n&quot;</span>, num);</span><br><span class="line">        num = S.<span class="built_in">numSquares</span>(<span class="number">13</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%d\n&quot;</span>, num);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Dynamic Programming</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="Dynamic Programming" scheme="https://even629.com/en/tags/Dynamic-Programming/"/>
    
    <category term="leetcode Hot 100" scheme="https://even629.com/en/tags/leetcode-Hot-100/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode Top 100 P118 Pascal&#39;s Triangle</title>
    <link href="https://even629.com/en/posts/118/"/>
    <id>https://even629.com/en/posts/118/</id>
    <published>2026-03-20T10:43:13.000Z</published>
    <updated>2026-03-20T10:43:13.000Z</updated>
    
    <content type="html"><![CDATA[<hr><details class="folding-tag" ><summary> Timeline </summary>            <div class='content'>            <div class="timeline blue"><div class='timeline-item headline'><div class='timeline-item-title'><div class='item-circle'><p>Timeline</p></div></div></div><div class='timeline-item'><div class='timeline-item-title'><div class='item-circle'><p>2026-03-20</p></div></div><div class='timeline-item-content'><p>init</p></div></div></div>            </div>          </details><blockquote>Dynamic Programming</blockquote><hr><p>Problem:</p><div class="tag link"><a class="link-card" title="P118 Pascal's Triangle" href="https://leetcode.cn/problems/pascals-triangle/description/?envType=study-plan-v2&envId=top-100-liked"><div class="left"><img loading="lazy" src="https://leetcode.cn/favicon.ico"/></div><div class="right"><p class="text">P118 Pascal's Triangle</p><p class="url">https://leetcode.cn/problems/pascals-triangle/description/?envType=study-plan-v2&envId=top-100-liked</p></div></a></div><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> std::vector;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">        vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; <span class="built_in">generate</span>(<span class="type">int</span> numRows)</span><br><span class="line">        &#123;</span><br><span class="line">                <span class="type">int</span> i, j, n;</span><br><span class="line">                <span class="type">int</span> last = <span class="number">0</span>;</span><br><span class="line">                vector&lt;vector&lt;<span class="type">int</span>&gt; &gt; res;</span><br><span class="line"></span><br><span class="line">                res.<span class="built_in">push_back</span>(&#123; <span class="number">1</span> &#125;);</span><br><span class="line">                <span class="keyword">if</span> (numRows == <span class="number">1</span>)</span><br><span class="line">                        <span class="keyword">return</span> res;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt; numRows; i++) &#123;</span><br><span class="line">                        vector&lt;<span class="type">int</span>&gt; &amp;last_line = res.<span class="built_in">back</span>();</span><br><span class="line">                        vector&lt;<span class="type">int</span>&gt; curr;</span><br><span class="line"></span><br><span class="line">                        last = <span class="number">0</span>;</span><br><span class="line">                        n = last_line.<span class="built_in">size</span>();</span><br><span class="line"></span><br><span class="line">                        <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; n; j++) &#123;</span><br><span class="line">                                curr.<span class="built_in">push_back</span>(last_line[j] + last);</span><br><span class="line">                                last = last_line[j];</span><br><span class="line">                        &#125;</span><br><span class="line"></span><br><span class="line">                        curr.<span class="built_in">push_back</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">                        res.<span class="built_in">push_back</span>(curr);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">return</span> res;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><!-- flag of hidden posts -->]]></content>
    
    
    <summary type="html">Dynamic Programming</summary>
    
    
    
    <category term="algorithm" scheme="https://even629.com/en/categories/algorithm/"/>
    
    
    <category term="algorithm" scheme="https://even629.com/en/tags/algorithm/"/>
    
    <category term="Dynamic Programming" scheme="https://even629.com/en/tags/Dynamic-Programming/"/>
    
    <category term="leetcode Hot 100" scheme="https://even629.com/en/tags/leetcode-Hot-100/"/>
    
  </entry>
  
</feed>
