<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Cold Boot</title>
    <subtitle>From power button to shell prompt -- how a computer actually starts</subtitle>
    <link rel="self" type="application/atom+xml" href="https://t34ch.tech/coldboot/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-01-26T00:00:00+00:00</updated>
    <id>https://t34ch.tech/coldboot/atom.xml</id>
    <entry xml:lang="en">
        <title>Your First Shell Script</title>
        <published>2025-01-26T00:00:00+00:00</published>
        <updated>2025-01-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/22-your-first-shell-script/"/>
        <id>https://t34ch.tech/coldboot/articles/22-your-first-shell-script/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/22-your-first-shell-script/">&lt;p&gt;You have been typing commands one at a time into the shell. That is fine for quick tasks, but when you need to run the same sequence of commands regularly -- or when the logic gets complex -- you write a shell script: a text file containing commands that the shell executes in order.&lt;&#x2F;p&gt;
&lt;p&gt;A shell script is not a compiled program. It is not written in a special language. It is the same commands you have been typing interactively, saved in a file. The shell reads the file line by line and executes each command exactly as if you had typed it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-shebang-line&quot;&gt;The Shebang Line&lt;&#x2F;h2&gt;
&lt;p&gt;Open your text editor and create a file called &lt;code&gt;hello.sh&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
echo &amp;quot;Hello from a shell script&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first line -- &lt;code&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt; -- is called the &lt;strong&gt;shebang&lt;&#x2F;strong&gt; (or hashbang). It tells the operating system which program should interpret this file. When you execute the script, the kernel reads these two bytes (&lt;code&gt;#!&lt;&#x2F;code&gt;) at the start, sees the path &lt;code&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt;, and launches bash with the script file as input.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Shebang&lt;&#x2F;strong&gt;
The character sequence #! at the very beginning of a script file, followed by the path to the interpreter program. When the kernel sees #! at the start of an executable file, it runs the specified interpreter and passes the script as its argument. The name comes from &quot;hash&quot; (#) and &quot;bang&quot; (!).
&lt;&#x2F;div&gt;
&lt;p&gt;The shebang must be the very first line. No blank lines before it. No spaces before the &lt;code&gt;#&lt;&#x2F;code&gt;. If it is missing or wrong, the system may try to interpret the file with the wrong shell, or fail to run it at all.&lt;&#x2F;p&gt;
&lt;p&gt;Common shebangs:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt; -- use bash specifically&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;#!&#x2F;bin&#x2F;sh&lt;&#x2F;code&gt; -- use the system&#x27;s POSIX shell (often dash)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3&lt;&#x2F;code&gt; -- use whatever python3 is in PATH&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The &lt;code&gt;#!&#x2F;usr&#x2F;bin&#x2F;env&lt;&#x2F;code&gt; form is useful for portability because it searches PATH rather than hardcoding the interpreter&#x27;s location.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 22.0 -- How the kernel processes the shebang&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 260&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;260&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- User types command --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;$ .&#x2F;hello.sh&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;33&quot; x2=&quot;290&quot; y2=&quot;50&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;!-- Kernel reads first bytes --&gt;
  &lt;rect x=&quot;170&quot; y=&quot;55&quot; width=&quot;240&quot; height=&quot;45&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;75&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Kernel reads first 2 bytes&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;92&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;#!&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;100&quot; x2=&quot;290&quot; y2=&quot;115&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;!-- Kernel reads path --&gt;
  &lt;rect x=&quot;150&quot; y=&quot;120&quot; width=&quot;280&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;138&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Reads interpreter path: &#x2F;bin&#x2F;bash&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;153&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;from the rest of line 1&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;160&quot; x2=&quot;290&quot; y2=&quot;175&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;!-- Kernel launches interpreter --&gt;
  &lt;rect x=&quot;130&quot; y=&quot;180&quot; width=&quot;320&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;198&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Executes: &#x2F;bin&#x2F;bash .&#x2F;hello.sh&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;213&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;bash reads the file and runs each line&lt;&#x2F;text&gt;
  &lt;!-- Note about bash ignoring shebang --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;245&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;bash ignores the #! line because # is a comment character in shell syntax.&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr22a&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;When you run a script, the kernel inspects the first two bytes. If they are #!, it reads the rest of line 1 as the path to the interpreter. It then launches that interpreter with the script file as an argument. The interpreter reads the file from the beginning, but since # starts a comment in most shells, the shebang line is harmlessly skipped.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;making-a-script-executable&quot;&gt;Making a Script Executable&lt;&#x2F;h2&gt;
&lt;p&gt;Before you can run &lt;code&gt;.&#x2F;hello.sh&lt;&#x2F;code&gt;, you need to give the file execute permission:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ chmod +x hello.sh
$ .&#x2F;hello.sh
Hello from a shell script
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;chmod +x&lt;&#x2F;code&gt; command sets the executable bit on the file. Without it, the kernel will refuse to run the file even though it contains valid commands. You can also run it explicitly through the interpreter:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ bash hello.sh
Hello from a shell script
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This does not require the execute bit because you are running &lt;code&gt;bash&lt;&#x2F;code&gt; (which is already executable) and passing the script as an argument. But the &lt;code&gt;.&#x2F;&lt;&#x2F;code&gt; form is cleaner and more conventional for scripts you intend to reuse.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;variables-in-scripts&quot;&gt;Variables in Scripts&lt;&#x2F;h2&gt;
&lt;p&gt;Shell variables work the same in scripts as they do interactively. Assign with &lt;code&gt;=&lt;&#x2F;code&gt; (no spaces around the equals sign), and reference with &lt;code&gt;$&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
name=&amp;quot;Cold Boot&amp;quot;
count=22
echo &amp;quot;This is article $count of the $name series&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can capture the output of a command into a variable using command substitution:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
today=$(date +%Y-%m-%d)
file_count=$(ls &#x2F;usr&#x2F;bin | wc -l)
echo &amp;quot;Today is $today&amp;quot;
echo &amp;quot;There are $file_count programs in &#x2F;usr&#x2F;bin&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;$(...)&lt;&#x2F;code&gt; syntax runs the command inside and replaces itself with the command&#x27;s output. The older backtick syntax &lt;code&gt;`command`&lt;&#x2F;code&gt; does the same thing but is harder to read and cannot be nested.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Command substitution&lt;&#x2F;strong&gt;
The syntax $(command) runs the enclosed command and replaces itself with the command&#x27;s standard output. This lets you capture the result of a command into a variable or embed it in a string. It is one of the most commonly used shell features.
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;quoting-rules&quot;&gt;Quoting Rules&lt;&#x2F;h3&gt;
&lt;p&gt;Quoting is a source of endless bugs in shell scripts. Here are the rules:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Double quotes&lt;&#x2F;strong&gt; (&lt;code&gt;&quot;...&quot;&lt;&#x2F;code&gt;) preserve the string as a single token but allow variable expansion:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ name=&amp;quot;Cold Boot&amp;quot;
$ echo &amp;quot;Welcome to $name&amp;quot;
Welcome to Cold Boot
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Single quotes&lt;&#x2F;strong&gt; (&lt;code&gt;&#x27;...&#x27;&lt;&#x2F;code&gt;) preserve the string literally. No variable expansion, no special characters:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &amp;#39;The price is $5.00&amp;#39;
The price is $5.00
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;No quotes&lt;&#x2F;strong&gt; cause the shell to split the value on whitespace and expand wildcards. This is almost never what you want:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ files=&amp;quot;one two three&amp;quot;
$ echo $files       # three separate arguments to echo
one two three
$ echo &amp;quot;$files&amp;quot;     # one argument containing spaces
one two three
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The practical rule: always double-quote your variables unless you have a specific reason not to. &lt;code&gt;&quot;$variable&quot;&lt;&#x2F;code&gt; is safe. &lt;code&gt;$variable&lt;&#x2F;code&gt; is a bug waiting to happen.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Always double-quote variables in shell scripts: &quot;$variable&quot;, not $variable. Unquoted variables are subject to word splitting and glob expansion, which causes subtle, hard-to-debug failures when values contain spaces or special characters.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;conditionals-if-statements&quot;&gt;Conditionals: if Statements&lt;&#x2F;h2&gt;
&lt;p&gt;Shell scripts can make decisions. The &lt;code&gt;if&lt;&#x2F;code&gt; statement tests a condition and runs different commands based on the result:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
if [ -f &#x2F;etc&#x2F;hostname ]; then
    echo &amp;quot;Hostname file exists&amp;quot;
    cat &#x2F;etc&#x2F;hostname
else
    echo &amp;quot;No hostname file found&amp;quot;
fi
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;[ ... ]&lt;&#x2F;code&gt; is actually a command (it is an alias for the &lt;code&gt;test&lt;&#x2F;code&gt; command). It evaluates the expression inside and exits with status 0 (true) or 1 (false). The &lt;code&gt;if&lt;&#x2F;code&gt; statement checks the exit status.&lt;&#x2F;p&gt;
&lt;p&gt;Common test expressions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[ -f file ]&lt;&#x2F;code&gt; -- true if file exists and is a regular file&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[ -d dir ]&lt;&#x2F;code&gt; -- true if directory exists&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[ -z &quot;$var&quot; ]&lt;&#x2F;code&gt; -- true if variable is empty or unset&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[ -n &quot;$var&quot; ]&lt;&#x2F;code&gt; -- true if variable is non-empty&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[ &quot;$a&quot; = &quot;$b&quot; ]&lt;&#x2F;code&gt; -- true if strings are equal&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[ &quot;$a&quot; != &quot;$b&quot; ]&lt;&#x2F;code&gt; -- true if strings differ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[ &quot;$x&quot; -eq &quot;$y&quot; ]&lt;&#x2F;code&gt; -- true if integers are equal&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[ &quot;$x&quot; -gt &quot;$y&quot; ]&lt;&#x2F;code&gt; -- true if x is greater than y&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 22.1 -- How if&#x2F;then&#x2F;else executes&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Condition test --&gt;
  &lt;rect x=&quot;190&quot; y=&quot;20&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;45&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;[ -f &#x2F;etc&#x2F;hostname ]&lt;&#x2F;text&gt;
  &lt;!-- Branch arrows --&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;60&quot; x2=&quot;130&quot; y2=&quot;100&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr22b)&quot;&#x2F;&gt;
  &lt;text x=&quot;170&quot; y=&quot;75&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;exit 0 (true)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;60&quot; x2=&quot;450&quot; y2=&quot;100&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr22c)&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;75&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;exit 1 (false)&lt;&#x2F;text&gt;
  &lt;!-- Then block --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;105&quot; width=&quot;200&quot; height=&quot;70&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;125&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;then&lt;&#x2F;text&gt;
  &lt;text x=&quot;140&quot; y=&quot;145&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;echo &quot;File exists&quot;&lt;&#x2F;text&gt;
  &lt;text x=&quot;140&quot; y=&quot;162&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;cat &#x2F;etc&#x2F;hostname&lt;&#x2F;text&gt;
  &lt;!-- Else block --&gt;
  &lt;rect x=&quot;340&quot; y=&quot;105&quot; width=&quot;200&quot; height=&quot;70&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;440&quot; y=&quot;125&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;else&lt;&#x2F;text&gt;
  &lt;text x=&quot;440&quot; y=&quot;150&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;echo &quot;Not found&quot;&lt;&#x2F;text&gt;
  &lt;!-- Converge --&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;175&quot; x2=&quot;290&quot; y2=&quot;210&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;440&quot; y1=&quot;175&quot; x2=&quot;290&quot; y2=&quot;210&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- fi --&gt;
  &lt;rect x=&quot;240&quot; y=&quot;210&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;230&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;fi&lt;&#x2F;text&gt;
  &lt;!-- Continue --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;240&quot; x2=&quot;290&quot; y2=&quot;260&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;280&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Execution continues after fi&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr22b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr22c&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The if statement runs the test command (inside the brackets). If the test exits with status 0, the &quot;then&quot; block runs. If it exits with any other status, the &quot;else&quot; block runs. Both paths converge at &quot;fi&quot;.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;exit-codes&quot;&gt;Exit Codes&lt;&#x2F;h2&gt;
&lt;p&gt;Every command returns an &lt;strong&gt;exit code&lt;&#x2F;strong&gt; when it finishes -- a number between 0 and 255. By convention:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;0&lt;&#x2F;strong&gt; means success&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Anything else&lt;&#x2F;strong&gt; means failure&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can check the most recent exit code with &lt;code&gt;$?&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls &#x2F;tmp
(file listing appears)
$ echo $?
0
$ ls &#x2F;nonexistent
ls: cannot access &amp;#39;&#x2F;nonexistent&amp;#39;: No such file or directory
$ echo $?
2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In your own scripts, you set the exit code with the &lt;code&gt;exit&lt;&#x2F;code&gt; command:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
if [ ! -f &amp;quot;$1&amp;quot; ]; then
    echo &amp;quot;Error: file $1 not found&amp;quot; &amp;gt;&amp;amp;2
    exit 1
fi
echo &amp;quot;Processing $1...&amp;quot;
exit 0
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice &lt;code&gt;&amp;gt;&amp;amp;2&lt;&#x2F;code&gt; on the error message -- that sends the text to stderr, which is the correct channel for error output. The &lt;code&gt;$1&lt;&#x2F;code&gt; is a special variable that holds the first command-line argument passed to the script.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Exit code&lt;&#x2F;strong&gt;
A number from 0 to 255 returned by every process when it terminates. Zero means success; any non-zero value means failure. The shell stores the most recent exit code in the special variable $?. Exit codes are how if statements, &amp;&amp; chains, and || chains make decisions.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;loops&quot;&gt;Loops&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;the-for-loop&quot;&gt;The for Loop&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;for&lt;&#x2F;code&gt; loop iterates over a list of items:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
for fruit in apple banana cherry; do
    echo &amp;quot;I like $fruit&amp;quot;
done
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Output:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;I like apple
I like banana
I like cherry
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can loop over files:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
for file in &#x2F;etc&#x2F;*.conf; do
    echo &amp;quot;Config file: $file&amp;quot;
done
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or over command output:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
for user in $(cat &#x2F;etc&#x2F;passwd | cut -d: -f1); do
    echo &amp;quot;User: $user&amp;quot;
done
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;the-while-loop&quot;&gt;The while Loop&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;while&lt;&#x2F;code&gt; loop runs as long as a condition is true:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
count=1
while [ &amp;quot;$count&amp;quot; -le 5 ]; do
    echo &amp;quot;Count: $count&amp;quot;
    count=$((count + 1))
done
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;$((...))&lt;&#x2F;code&gt; syntax performs arithmetic. Without it, the shell treats everything as strings.&lt;&#x2F;p&gt;
&lt;p&gt;A common pattern is reading a file line by line:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
while read -r line; do
    echo &amp;quot;Line: $line&amp;quot;
done &amp;lt; &#x2F;etc&#x2F;hostname
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt; &#x2F;etc&#x2F;hostname&lt;&#x2F;code&gt; at the end redirects the file into the while loop&#x27;s stdin. The &lt;code&gt;read -r&lt;&#x2F;code&gt; command reads one line at a time into the variable &lt;code&gt;line&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 22.2 -- for loop vs. while loop execution flow&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- for loop (left) --&gt;
&lt;p&gt;&lt;text x=&quot;145&quot; y=&quot;25&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;for loop&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;60&quot; y=&quot;40&quot; width=&quot;170&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;60&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;list: [a, b, c]&lt;&#x2F;text&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;70&quot; x2=&quot;145&quot; y2=&quot;85&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;rect x=&quot;70&quot; y=&quot;90&quot; width=&quot;150&quot; height=&quot;30&quot; rx=&quot;15&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;110&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;next item?&lt;&#x2F;text&gt;
  &lt;!-- Yes path --&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;120&quot; x2=&quot;145&quot; y2=&quot;140&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22b)&quot;&#x2F;&gt;
  &lt;text x=&quot;158&quot; y=&quot;134&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot;&gt;yes&lt;&#x2F;text&gt;
  &lt;rect x=&quot;70&quot; y=&quot;145&quot; width=&quot;150&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;162&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;item=a&lt;&#x2F;text&gt;
  &lt;text x=&quot;145&quot; y=&quot;175&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;run body&lt;&#x2F;text&gt;
  &lt;!-- Loop back --&gt;
  &lt;line x1=&quot;70&quot; y1=&quot;162&quot; x2=&quot;40&quot; y2=&quot;162&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;40&quot; y1=&quot;162&quot; x2=&quot;40&quot; y2=&quot;105&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;40&quot; y1=&quot;105&quot; x2=&quot;70&quot; y2=&quot;105&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr22d)&quot;&#x2F;&gt;
  &lt;!-- No path --&gt;
  &lt;line x1=&quot;220&quot; y1=&quot;105&quot; x2=&quot;250&quot; y2=&quot;105&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;250&quot; y1=&quot;105&quot; x2=&quot;250&quot; y2=&quot;220&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22c)&quot;&#x2F;&gt;
  &lt;text x=&quot;258&quot; y=&quot;100&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot;&gt;no&lt;&#x2F;text&gt;
  &lt;rect x=&quot;210&quot; y=&quot;225&quot; width=&quot;80&quot; height=&quot;25&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;250&quot; y=&quot;242&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;done&lt;&#x2F;text&gt;
  &lt;!-- while loop (right) --&gt;
&lt;p&gt;&lt;text x=&quot;435&quot; y=&quot;25&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;while loop&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;350&quot; y=&quot;40&quot; width=&quot;170&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;60&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;initial: count=1&lt;&#x2F;text&gt;
  &lt;line x1=&quot;435&quot; y1=&quot;70&quot; x2=&quot;435&quot; y2=&quot;85&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;rect x=&quot;355&quot; y=&quot;90&quot; width=&quot;160&quot; height=&quot;30&quot; rx=&quot;15&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;110&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;count -le 5 ?&lt;&#x2F;text&gt;
  &lt;!-- Yes path --&gt;
  &lt;line x1=&quot;435&quot; y1=&quot;120&quot; x2=&quot;435&quot; y2=&quot;140&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22b)&quot;&#x2F;&gt;
  &lt;text x=&quot;448&quot; y=&quot;134&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot;&gt;yes&lt;&#x2F;text&gt;
  &lt;rect x=&quot;360&quot; y=&quot;145&quot; width=&quot;150&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;162&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;echo, count++&lt;&#x2F;text&gt;
  &lt;text x=&quot;435&quot; y=&quot;175&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;run body&lt;&#x2F;text&gt;
  &lt;!-- Loop back --&gt;
  &lt;line x1=&quot;510&quot; y1=&quot;162&quot; x2=&quot;540&quot; y2=&quot;162&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;540&quot; y1=&quot;162&quot; x2=&quot;540&quot; y2=&quot;105&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;540&quot; y1=&quot;105&quot; x2=&quot;515&quot; y2=&quot;105&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr22e)&quot;&#x2F;&gt;
  &lt;!-- No path --&gt;
  &lt;line x1=&quot;355&quot; y1=&quot;105&quot; x2=&quot;330&quot; y2=&quot;105&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;330&quot; y1=&quot;105&quot; x2=&quot;330&quot; y2=&quot;220&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22c)&quot;&#x2F;&gt;
  &lt;text x=&quot;340&quot; y=&quot;100&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot;&gt;no&lt;&#x2F;text&gt;
  &lt;rect x=&quot;290&quot; y=&quot;225&quot; width=&quot;80&quot; height=&quot;25&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;330&quot; y=&quot;242&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;done&lt;&#x2F;text&gt;
  &lt;!-- Summary --&gt;
&lt;p&gt;&lt;text x=&quot;145&quot; y=&quot;280&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Iterates over a fixed list&lt;&#x2F;text&gt;
&lt;text x=&quot;435&quot; y=&quot;280&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Repeats while condition is true&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr22d&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr22e&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;0&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M8,0 L0,3 L8,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A for loop steps through a fixed list of items, running the body once per item. A while loop re-tests its condition before each iteration and stops when the condition becomes false.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting It All Together&lt;&#x2F;h2&gt;
&lt;p&gt;Here is a complete, practical shell script that combines everything from this article and the previous ones in the series. It checks disk usage on a set of directories and warns if any exceed a threshold:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
# disk-check.sh -- warn about directories using too much space

THRESHOLD=80   # percent
DIRS=&amp;quot;&#x2F;home &#x2F;var &#x2F;tmp&amp;quot;

echo &amp;quot;Disk usage check -- $(date)&amp;quot;
echo &amp;quot;Threshold: ${THRESHOLD}%&amp;quot;
echo &amp;quot;---&amp;quot;

warnings=0

for dir in $DIRS; do
    if [ ! -d &amp;quot;$dir&amp;quot; ]; then
        echo &amp;quot;SKIP: $dir does not exist&amp;quot; &amp;gt;&amp;amp;2
        continue
    fi

    usage=$(df &amp;quot;$dir&amp;quot; | tail -1 | awk &amp;#39;{print $5}&amp;#39; | tr -d &amp;#39;%&amp;#39;)

    if [ &amp;quot;$usage&amp;quot; -gt &amp;quot;$THRESHOLD&amp;quot; ]; then
        echo &amp;quot;WARNING: $dir is at ${usage}% (exceeds ${THRESHOLD}%)&amp;quot;
        warnings=$((warnings + 1))
    else
        echo &amp;quot;OK: $dir is at ${usage}%&amp;quot;
    fi
done

echo &amp;quot;---&amp;quot;
if [ &amp;quot;$warnings&amp;quot; -gt 0 ]; then
    echo &amp;quot;$warnings warning(s) found&amp;quot;
    exit 1
else
    echo &amp;quot;All directories within limits&amp;quot;
    exit 0
fi
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This script uses:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A shebang (&lt;code&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Variables (&lt;code&gt;THRESHOLD&lt;&#x2F;code&gt;, &lt;code&gt;DIRS&lt;&#x2F;code&gt;, &lt;code&gt;warnings&lt;&#x2F;code&gt;, &lt;code&gt;usage&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Command substitution (&lt;code&gt;$(date)&lt;&#x2F;code&gt;, &lt;code&gt;$(df ... | awk ...)&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;A for loop&lt;&#x2F;li&gt;
&lt;li&gt;Conditionals with &lt;code&gt;if&#x2F;else&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;File tests (&lt;code&gt;[ ! -d &quot;$dir&quot; ]&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Integer comparison (&lt;code&gt;[ &quot;$usage&quot; -gt &quot;$THRESHOLD&quot; ]&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Stderr for errors (&lt;code&gt;&amp;gt;&amp;amp;2&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Arithmetic (&lt;code&gt;$((warnings + 1))&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Exit codes (0 for success, 1 for warnings)&lt;&#x2F;li&gt;
&lt;li&gt;A pipeline (&lt;code&gt;df | tail | awk | tr&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 22.3 -- Data flow through the disk-check script&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 320&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;320&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Script entry --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;10&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;30&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;disk-check.sh&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;40&quot; x2=&quot;290&quot; y2=&quot;55&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;!-- For loop over dirs --&gt;
  &lt;rect x=&quot;180&quot; y=&quot;60&quot; width=&quot;220&quot; height=&quot;30&quot; rx=&quot;15&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;80&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;for dir in &#x2F;home &#x2F;var &#x2F;tmp&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;90&quot; x2=&quot;290&quot; y2=&quot;105&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;!-- Check exists --&gt;
  &lt;rect x=&quot;195&quot; y=&quot;110&quot; width=&quot;190&quot; height=&quot;25&quot; rx=&quot;12&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;127&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;directory exists?&lt;&#x2F;text&gt;
  &lt;!-- No: skip --&gt;
  &lt;line x1=&quot;385&quot; y1=&quot;122&quot; x2=&quot;430&quot; y2=&quot;122&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;460&quot; y=&quot;127&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;skip&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;135&quot; x2=&quot;290&quot; y2=&quot;150&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr22b)&quot;&#x2F;&gt;
  &lt;!-- Pipeline --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;155&quot; width=&quot;420&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;175&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;df &#x2F;home | tail -1 | awk &#x27;{print $5}&#x27; | tr -d &#x27;%&#x27;&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;195&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;extracts usage percentage as a plain number&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;205&quot; x2=&quot;290&quot; y2=&quot;218&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr22a)&quot;&#x2F;&gt;
  &lt;!-- Compare --&gt;
  &lt;rect x=&quot;185&quot; y=&quot;222&quot; width=&quot;210&quot; height=&quot;25&quot; rx=&quot;12&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;239&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;usage &gt; threshold?&lt;&#x2F;text&gt;
  &lt;!-- Yes: warning --&gt;
  &lt;line x1=&quot;185&quot; y1=&quot;234&quot; x2=&quot;100&quot; y2=&quot;265&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22c)&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;280&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;WARNING&lt;&#x2F;text&gt;
  &lt;!-- No: OK --&gt;
  &lt;line x1=&quot;395&quot; y1=&quot;234&quot; x2=&quot;480&quot; y2=&quot;265&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr22b)&quot;&#x2F;&gt;
  &lt;text x=&quot;500&quot; y=&quot;280&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;OK&lt;&#x2F;text&gt;
  &lt;!-- Exit --&gt;
  &lt;line x1=&quot;80&quot; y1=&quot;288&quot; x2=&quot;290&quot; y2=&quot;308&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;500&quot; y1=&quot;288&quot; x2=&quot;290&quot; y2=&quot;308&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;318&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;exit 1 (warnings) or exit 0 (all clear)&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The script loops over directories, runs a pipeline to extract usage percentages, compares each against a threshold, and exits with an appropriate status code. Every concept from the last five articles appears in this one script.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;script-arguments&quot;&gt;Script Arguments&lt;&#x2F;h2&gt;
&lt;p&gt;Scripts can accept arguments from the command line. They are available as special variables:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$0&lt;&#x2F;code&gt; -- the script&#x27;s own name&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;$1&lt;&#x2F;code&gt;, &lt;code&gt;$2&lt;&#x2F;code&gt;, &lt;code&gt;$3&lt;&#x2F;code&gt;, ... -- positional arguments&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;$#&lt;&#x2F;code&gt; -- the number of arguments&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;$@&lt;&#x2F;code&gt; -- all arguments as separate words&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
echo &amp;quot;Script: $0&amp;quot;
echo &amp;quot;First argument: $1&amp;quot;
echo &amp;quot;Second argument: $2&amp;quot;
echo &amp;quot;Total arguments: $#&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre&gt;&lt;code&gt;$ .&#x2F;args.sh hello world
Script: .&#x2F;args.sh
First argument: hello
Second argument: world
Total arguments: 2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A well-behaved script checks that it received the right number of arguments:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
if [ $# -lt 1 ]; then
    echo &amp;quot;Usage: $0 &amp;lt;filename&amp;gt;&amp;quot; &amp;gt;&amp;amp;2
    exit 1
fi
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;debugging-scripts&quot;&gt;Debugging Scripts&lt;&#x2F;h2&gt;
&lt;p&gt;When a script does not work, add &lt;code&gt;set -x&lt;&#x2F;code&gt; near the top. This makes bash print every command before it runs, showing you exactly what is happening:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
set -x
name=&amp;quot;world&amp;quot;
echo &amp;quot;Hello, $name&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Output:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;+ name=world
+ echo &amp;#39;Hello, world&amp;#39;
Hello, world
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each line prefixed with &lt;code&gt;+&lt;&#x2F;code&gt; is bash showing you the command after variable expansion but before execution. This is invaluable for finding quoting bugs and logic errors.&lt;&#x2F;p&gt;
&lt;p&gt;Another useful setting is &lt;code&gt;set -e&lt;&#x2F;code&gt;, which makes the script stop immediately if any command fails (returns a non-zero exit code). Combined with &lt;code&gt;set -u&lt;&#x2F;code&gt; (treat unset variables as errors), these three settings catch most common scripting mistakes:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;#!&#x2F;bin&#x2F;bash
set -euo pipefail
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;pipefail&lt;&#x2F;code&gt; option makes a pipeline return the exit code of the last failing command, rather than the last command overall.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Start your scripts with `set -euo pipefail` until you have a reason not to. These settings catch unset variables, failed commands, and broken pipes -- the three most common sources of silent script failures.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-you-have-learned&quot;&gt;What You Have Learned&lt;&#x2F;h2&gt;
&lt;p&gt;A shell script is a text file of commands with a shebang line that tells the kernel which interpreter to use. Variables hold values, and command substitution captures program output. Conditionals use &lt;code&gt;[ ... ]&lt;&#x2F;code&gt; (the test command) and check exit codes. Loops iterate over lists (for) or repeat while a condition holds (while). Exit codes communicate success (0) or failure (non-zero) to the calling program. Script arguments arrive in &lt;code&gt;$1&lt;&#x2F;code&gt;, &lt;code&gt;$2&lt;&#x2F;code&gt;, and so on.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;This is the final article in the Cold Boot series. You have traveled from the first pulse of electricity through voltage rails and reset vectors, past the BIOS and bootloader, into the kernel and init system, through process management and permissions, and now into the shell where you write your own commands.&lt;&#x2F;p&gt;
&lt;p&gt;The journey from power-on to a running shell script touches every layer of a computer. Electricity becomes bits. Bits become instructions. Instructions become firmware. Firmware finds a bootloader. The bootloader loads a kernel. The kernel starts init. Init launches services. A terminal opens. A shell starts its read-execute loop. And now you can write a script that orchestrates all of it.&lt;&#x2F;p&gt;
&lt;p&gt;Every command you type from here forward sits on top of the entire stack you have just learned. You are not a passive user anymore. You understand what happens underneath.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;coldboot&#x2F;&quot;&gt;Back to the Cold Boot series index&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Environment</title>
        <published>2025-01-25T00:00:00+00:00</published>
        <updated>2025-01-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/21-the-environment/"/>
        <id>https://t34ch.tech/coldboot/articles/21-the-environment/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/21-the-environment/">&lt;p&gt;Every process on a Unix system carries a bag of named values. These values -- called environment variables -- tell programs where to find things, how to behave, and who is running them. They are the primary mechanism for passing configuration from a parent process to its children without modifying any files or passing command-line arguments.&lt;&#x2F;p&gt;
&lt;p&gt;You have already seen one: PATH, the list of directories the shell searches for programs. Now we will look at the full picture.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-an-environment-variable-is&quot;&gt;What an Environment Variable Is&lt;&#x2F;h2&gt;
&lt;p&gt;Think of an environment variable as a sticky note attached to a process. It has a name and a value, both plain text. The name is conventionally uppercase. The value can be anything: a directory path, a number, a comma-separated list, an empty string.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo $HOME
&#x2F;home&#x2F;user
$ echo $USER
user
$ echo $SHELL
&#x2F;bin&#x2F;bash
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;$&lt;&#x2F;code&gt; prefix tells the shell to substitute the variable&#x27;s value in place of its name. Without the &lt;code&gt;$&lt;&#x2F;code&gt;, the shell treats the text as a literal string:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo HOME
HOME
$ echo $HOME
&#x2F;home&#x2F;user
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Environment variable&lt;&#x2F;strong&gt;
A named key-value pair carried by every process. Environment variables are inherited by child processes and are the standard Unix mechanism for passing configuration without using files or command-line flags. By convention, names are uppercase with underscores.
&lt;&#x2F;div&gt;
&lt;p&gt;You can list every environment variable currently set in your shell:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ env
HOME=&#x2F;home&#x2F;user
PATH=&#x2F;usr&#x2F;local&#x2F;bin:&#x2F;usr&#x2F;bin:&#x2F;bin
SHELL=&#x2F;bin&#x2F;bash
USER=user
TERM=xterm-256color
LANG=en_US.UTF-8
...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There may be dozens or even hundreds. Each one was set by something during your login process or shell startup.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 21.0 -- The environment as a key-value store&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Title --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;30&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Process Environment Block&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Table header --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;45&quot; width=&quot;200&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;#494D52&quot;&#x2F;&gt;
  &lt;text x=&quot;180&quot; y=&quot;62&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;NAME&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;45&quot; width=&quot;220&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;#494D52&quot;&#x2F;&gt;
  &lt;text x=&quot;390&quot; y=&quot;62&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;VALUE&lt;&#x2F;text&gt;
  &lt;!-- Rows --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;70&quot; width=&quot;200&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;87&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;HOME&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;70&quot; width=&quot;220&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;87&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;&#x2F;home&#x2F;user&lt;&#x2F;text&gt;
  &lt;rect x=&quot;80&quot; y=&quot;95&quot; width=&quot;200&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;112&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;PATH&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;95&quot; width=&quot;220&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;112&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;&#x2F;usr&#x2F;local&#x2F;bin:&#x2F;usr&#x2F;bin:&#x2F;bin&lt;&#x2F;text&gt;
  &lt;rect x=&quot;80&quot; y=&quot;120&quot; width=&quot;200&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;137&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;USER&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;120&quot; width=&quot;220&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;137&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;user&lt;&#x2F;text&gt;
  &lt;rect x=&quot;80&quot; y=&quot;145&quot; width=&quot;200&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;162&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;SHELL&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;145&quot; width=&quot;220&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;162&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;text&gt;
  &lt;rect x=&quot;80&quot; y=&quot;170&quot; width=&quot;200&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;187&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;LANG&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;170&quot; width=&quot;220&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;187&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;en_US.UTF-8&lt;&#x2F;text&gt;
  &lt;rect x=&quot;80&quot; y=&quot;195&quot; width=&quot;200&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;212&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;TERM&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;195&quot; width=&quot;220&quot; height=&quot;25&quot; rx=&quot;0&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;212&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;xterm-256color&lt;&#x2F;text&gt;
  &lt;!-- More indicator --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;240&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;... and dozens more&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Note --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;268&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Every process gets its own copy of this table at birth.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The environment is a table of name-value pairs. Each process gets its own copy when it is created. Changes to one process&#x27;s environment do not affect any other process.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;shell-variables-vs-environment-variables&quot;&gt;Shell Variables vs. Environment Variables&lt;&#x2F;h2&gt;
&lt;p&gt;The shell actually maintains two kinds of variables. Understanding the difference is important.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;strong&gt;shell variable&lt;&#x2F;strong&gt; exists only inside the shell process. It is not passed to child processes. You create one by simple assignment:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ color=blue
$ echo $color
blue
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An &lt;strong&gt;environment variable&lt;&#x2F;strong&gt; is a shell variable that has been marked for export. It is copied into the environment of every child process the shell starts. You mark a variable for export with the &lt;code&gt;export&lt;&#x2F;code&gt; command:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ export color=blue
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or export an existing variable:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ color=blue
$ export color
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The difference matters when you run programs. A program started by the shell only sees exported variables:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ secret=hidden
$ export visible=shown
$ bash -c &amp;#39;echo &amp;quot;secret=$secret visible=$visible&amp;quot;&amp;#39;
secret= visible=shown
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The inner bash (a child process) can see &lt;code&gt;visible&lt;&#x2F;code&gt; because it was exported. It cannot see &lt;code&gt;secret&lt;&#x2F;code&gt; because it was a plain shell variable.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: export&lt;&#x2F;strong&gt;
A shell built-in command that marks a variable for inclusion in the environment of child processes. Without export, a variable exists only within the current shell. With export, it is inherited by every program the shell launches.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 21.1 -- Shell variables vs. environment variables&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Parent shell --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;20&quot; width=&quot;240&quot; height=&quot;160&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;45&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Parent shell (bash)&lt;&#x2F;text&gt;
  &lt;!-- Shell vars --&gt;
&lt;p&gt;&lt;text x=&quot;40&quot; y=&quot;70&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Shell variables:&lt;&#x2F;text&gt;
&lt;text x=&quot;40&quot; y=&quot;88&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot;&gt;secret=hidden&lt;&#x2F;text&gt;
&lt;text x=&quot;40&quot; y=&quot;106&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot;&gt;temp=working&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Env vars --&gt;
&lt;p&gt;&lt;text x=&quot;40&quot; y=&quot;130&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Environment variables:&lt;&#x2F;text&gt;
&lt;text x=&quot;40&quot; y=&quot;148&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;PATH=&#x2F;usr&#x2F;bin:...&lt;&#x2F;text&gt;
&lt;text x=&quot;40&quot; y=&quot;166&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;visible=shown&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Arrow: fork --&gt;
  &lt;line x1=&quot;260&quot; y1=&quot;100&quot; x2=&quot;320&quot; y2=&quot;100&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr21a)&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;90&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;fork+exec&lt;&#x2F;text&gt;
  &lt;!-- Child process --&gt;
  &lt;rect x=&quot;330&quot; y=&quot;20&quot; width=&quot;230&quot; height=&quot;160&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;445&quot; y=&quot;45&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Child process (ls)&lt;&#x2F;text&gt;
  &lt;!-- What child sees --&gt;
&lt;p&gt;&lt;text x=&quot;350&quot; y=&quot;70&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Inherited environment:&lt;&#x2F;text&gt;
&lt;text x=&quot;350&quot; y=&quot;88&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;PATH=&#x2F;usr&#x2F;bin:...&lt;&#x2F;text&gt;
&lt;text x=&quot;350&quot; y=&quot;106&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;visible=shown&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- What child does NOT see --&gt;
&lt;p&gt;&lt;text x=&quot;350&quot; y=&quot;135&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;NOT inherited:&lt;&#x2F;text&gt;
&lt;text x=&quot;350&quot; y=&quot;153&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot;&gt;secret&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;153&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;(not exported)&lt;&#x2F;text&gt;
&lt;text x=&quot;350&quot; y=&quot;168&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot;&gt;temp&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;168&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;(not exported)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Legend --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;210&quot; width=&quot;12&quot; height=&quot;12&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;221&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Exported (inherited by children)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;60&quot; y=&quot;235&quot; width=&quot;12&quot; height=&quot;12&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;246&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Not exported (shell-only, invisible to children)&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;272&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;The child gets a COPY. Changes in the child do not affect the parent.&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr21a&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;When the shell forks a child process, only exported variables are copied into the child&#x27;s environment. Plain shell variables stay behind in the parent. The child gets a copy, not a reference -- changes in the child never propagate back to the parent.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;div class=&quot;remember&quot;&gt;
Inheritance flows one way: from parent to child. A child process can never modify its parent&#x27;s environment. If you set a variable inside a script, the calling shell will not see the change after the script exits. This is a common source of confusion for beginners.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-essential-variables&quot;&gt;The Essential Variables&lt;&#x2F;h2&gt;
&lt;p&gt;Some environment variables are so common that nearly every program recognizes them. Here are the ones you need to know:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;path&quot;&gt;PATH&lt;&#x2F;h3&gt;
&lt;p&gt;The most important environment variable. It contains a colon-separated list of directories that the shell searches when you type a command name. We covered this in Article 18.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo $PATH
&#x2F;usr&#x2F;local&#x2F;bin:&#x2F;usr&#x2F;bin:&#x2F;bin:&#x2F;usr&#x2F;sbin:&#x2F;sbin
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To add a directory, you append to PATH:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ export PATH=&amp;quot;$PATH:&#x2F;home&#x2F;user&#x2F;bin&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;$PATH&lt;&#x2F;code&gt; expands to the current value, and you concatenate your new directory after a colon. Put your addition at the end so that system programs are found first, or at the beginning if you want your version to take priority.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;home&quot;&gt;HOME&lt;&#x2F;h3&gt;
&lt;p&gt;The path to the current user&#x27;s home directory. Programs use it to find configuration files. The &lt;code&gt;~&lt;&#x2F;code&gt; shortcut in the shell expands to this value.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo $HOME
&#x2F;home&#x2F;user
$ echo ~
&#x2F;home&#x2F;user
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;user&quot;&gt;USER&lt;&#x2F;h3&gt;
&lt;p&gt;The name of the currently logged-in user. Programs use it for logging, file ownership, and access control decisions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;shell&quot;&gt;SHELL&lt;&#x2F;h3&gt;
&lt;p&gt;The path to the user&#x27;s default login shell, as set in &lt;code&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;code&gt;. Note that this is the default shell, not necessarily the shell currently running. If you start zsh from inside bash, &lt;code&gt;$SHELL&lt;&#x2F;code&gt; still says &lt;code&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;editor-and-visual&quot;&gt;EDITOR and VISUAL&lt;&#x2F;h3&gt;
&lt;p&gt;The user&#x27;s preferred text editor. Many programs (like &lt;code&gt;git commit&lt;&#x2F;code&gt; with no &lt;code&gt;-m&lt;&#x2F;code&gt; flag) consult these variables to decide which editor to open.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ export EDITOR=vim
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;lang-and-lc&quot;&gt;LANG and LC_*&lt;&#x2F;h3&gt;
&lt;p&gt;Language and locale settings. They control how programs display dates, numbers, currency, and sort text. &lt;code&gt;LANG=en_US.UTF-8&lt;&#x2F;code&gt; means English, United States, using the UTF-8 character encoding.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;term&quot;&gt;TERM&lt;&#x2F;h3&gt;
&lt;p&gt;The type of terminal emulator. Programs that draw to the screen (like &lt;code&gt;vim&lt;&#x2F;code&gt; or &lt;code&gt;top&lt;&#x2F;code&gt;) read this to know which escape codes to use for colors, cursor movement, and screen clearing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setting-variables-for-a-single-command&quot;&gt;Setting Variables for a Single Command&lt;&#x2F;h2&gt;
&lt;p&gt;You can set an environment variable for just one command without affecting your shell session:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ LANG=C sort data.txt
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;LANG=C&lt;&#x2F;code&gt; assignment is placed before the command name. The variable is set only in the environment of &lt;code&gt;sort&lt;&#x2F;code&gt; and reverts to its previous value (or unset state) when &lt;code&gt;sort&lt;&#x2F;code&gt; exits.&lt;&#x2F;p&gt;
&lt;p&gt;This pattern is useful for overriding behavior temporarily:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ TZ=UTC date
$ LC_ALL=C grep &amp;quot;[A-Z]&amp;quot; file.txt
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;how-the-environment-is-built-at-login&quot;&gt;How the Environment Is Built at Login&lt;&#x2F;h2&gt;
&lt;p&gt;When you log in, the environment does not appear from nowhere. It is constructed in layers, with each layer adding or overriding variables.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Layer 1: The kernel.&lt;&#x2F;strong&gt; The kernel sets a minimal environment when the login process starts. This includes the terminal type and some basic system information.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Layer 2: PAM and the login process.&lt;&#x2F;strong&gt; The login system reads &lt;code&gt;&#x2F;etc&#x2F;environment&lt;&#x2F;code&gt; and sets variables found there. This is a system-wide configuration file.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Layer 3: The login shell.&lt;&#x2F;strong&gt; If you are using bash, the login shell reads &lt;code&gt;&#x2F;etc&#x2F;profile&lt;&#x2F;code&gt; (system-wide defaults), then one of &lt;code&gt;~&#x2F;.bash_profile&lt;&#x2F;code&gt;, &lt;code&gt;~&#x2F;.bash_login&lt;&#x2F;code&gt;, or &lt;code&gt;~&#x2F;.profile&lt;&#x2F;code&gt; (user-specific, in that priority order). These scripts typically set PATH, EDITOR, and other session-wide variables.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Layer 4: Interactive shell startup.&lt;&#x2F;strong&gt; Each new interactive bash shell (like opening a new terminal tab) reads &lt;code&gt;~&#x2F;.bashrc&lt;&#x2F;code&gt;. This file typically contains aliases, shell functions, prompt customization, and other per-shell settings.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 21.2 -- Startup file loading order for bash&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Login shell column --&gt;
&lt;p&gt;&lt;text x=&quot;160&quot; y=&quot;25&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Login shell&lt;&#x2F;text&gt;
&lt;text x=&quot;160&quot; y=&quot;40&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(first shell after login)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;60&quot; y=&quot;55&quot; width=&quot;200&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;75&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;etc&#x2F;environment&lt;&#x2F;text&gt;
  &lt;line x1=&quot;160&quot; y1=&quot;85&quot; x2=&quot;160&quot; y2=&quot;95&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr21b)&quot;&#x2F;&gt;
  &lt;rect x=&quot;60&quot; y=&quot;100&quot; width=&quot;200&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;120&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;etc&#x2F;profile&lt;&#x2F;text&gt;
  &lt;line x1=&quot;160&quot; y1=&quot;130&quot; x2=&quot;160&quot; y2=&quot;140&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr21b)&quot;&#x2F;&gt;
  &lt;rect x=&quot;60&quot; y=&quot;145&quot; width=&quot;200&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;165&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;~&#x2F;.bash_profile&lt;&#x2F;text&gt;
  &lt;line x1=&quot;160&quot; y1=&quot;175&quot; x2=&quot;160&quot; y2=&quot;185&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; marker-end=&quot;url(#arr21b)&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;160&quot; y=&quot;205&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;(often sources ~&#x2F;.bashrc)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Interactive non-login column --&gt;
&lt;p&gt;&lt;text x=&quot;430&quot; y=&quot;25&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Non-login interactive&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;40&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(new terminal window)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;330&quot; y=&quot;100&quot; width=&quot;200&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;120&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;~&#x2F;.bashrc&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;430&quot; y=&quot;155&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;That&#x27;s it.&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Typical .bash_profile content --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;225&quot; width=&quot;500&quot; height=&quot;90&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot;&#x2F;&gt;
  &lt;text x=&quot;60&quot; y=&quot;248&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;# Typical ~&#x2F;.bash_profile&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;268&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;export PATH=&quot;$HOME&#x2F;bin:$PATH&quot;&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;288&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;export EDITOR=vim&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;308&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;source ~&#x2F;.bashrc&lt;&#x2F;text&gt;
  &lt;text x=&quot;230&quot; y=&quot;308&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;# load aliases and prompt&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr21b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A login shell reads system-wide files first, then user-specific files. A non-login interactive shell reads only ~&#x2F;.bashrc. A common pattern is for ~&#x2F;.bash_profile to source ~&#x2F;.bashrc so that all settings are available in both scenarios.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The usual best practice is to put environment variable exports (PATH, EDITOR, etc.) in &lt;code&gt;~&#x2F;.bash_profile&lt;&#x2F;code&gt; or &lt;code&gt;~&#x2F;.profile&lt;&#x2F;code&gt;, and put aliases, functions, and prompt settings in &lt;code&gt;~&#x2F;.bashrc&lt;&#x2F;code&gt;. Then have &lt;code&gt;~&#x2F;.bash_profile&lt;&#x2F;code&gt; source &lt;code&gt;~&#x2F;.bashrc&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;# In ~&#x2F;.bash_profile:
export PATH=&amp;quot;$HOME&#x2F;bin:$PATH&amp;quot;
export EDITOR=vim

# Load interactive settings too
if [ -f ~&#x2F;.bashrc ]; then
    source ~&#x2F;.bashrc
fi
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: source&lt;&#x2F;strong&gt;
A shell built-in that reads and executes a file in the current shell, rather than starting a new process. Unlike running a script normally, sourcing preserves variable changes and function definitions in the current shell. The dot command (.) is an alias for source.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;unsetting-variables&quot;&gt;Unsetting Variables&lt;&#x2F;h2&gt;
&lt;p&gt;To remove a variable from the environment, use &lt;code&gt;unset&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ export DEBUG=1
$ echo $DEBUG
1
$ unset DEBUG
$ echo $DEBUG

&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After &lt;code&gt;unset&lt;&#x2F;code&gt;, the variable no longer exists. This is different from setting it to an empty string:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ export DEBUG=&amp;quot;&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An empty variable still exists in the environment. An unset variable is absent entirely. Some programs treat these differently.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-process-cannot-modify-its-parent&quot;&gt;A Process Cannot Modify Its Parent&lt;&#x2F;h2&gt;
&lt;p&gt;This point is so important it deserves its own section. When a process is created with &lt;code&gt;fork()&lt;&#x2F;code&gt;, it gets a copy of the parent&#x27;s environment. Changes to that copy are private. They do not propagate back to the parent.&lt;&#x2F;p&gt;
&lt;p&gt;This means if you run a script that sets a variable, the variable disappears when the script exits:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ cat set_color.sh
#!&#x2F;bin&#x2F;bash
export COLOR=red
echo &amp;quot;Inside script: COLOR=$COLOR&amp;quot;

$ bash set_color.sh
Inside script: COLOR=red
$ echo $COLOR

$
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The variable &lt;code&gt;COLOR&lt;&#x2F;code&gt; was set inside the child bash process that ran the script. When that process exited, its environment was destroyed. The parent shell never saw the change.&lt;&#x2F;p&gt;
&lt;p&gt;If you want a script to modify the current shell&#x27;s environment, you must &lt;strong&gt;source&lt;&#x2F;strong&gt; it:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ source set_color.sh
Inside script: COLOR=red
$ echo $COLOR
red
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sourcing reads the file and executes it in the current shell, not in a child. Now the &lt;code&gt;export COLOR=red&lt;&#x2F;code&gt; command runs in your actual shell, so the variable persists.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 21.3 -- Running vs. sourcing a script&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Left side: run --&gt;
&lt;p&gt;&lt;text x=&quot;145&quot; y=&quot;25&quot; fill=&quot;#C0392B&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;bash script.sh&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;30&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;70&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;85&quot; y=&quot;60&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Parent shell&lt;&#x2F;text&gt;
  &lt;text x=&quot;85&quot; y=&quot;80&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;COLOR=(unset)&lt;&#x2F;text&gt;
  &lt;text x=&quot;85&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;unchanged&lt;&#x2F;text&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;75&quot; x2=&quot;165&quot; y2=&quot;75&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr21c)&quot;&#x2F;&gt;
  &lt;text x=&quot;152&quot; y=&quot;68&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;fork&lt;&#x2F;text&gt;
  &lt;rect x=&quot;170&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;70&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;225&quot; y=&quot;60&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Child bash&lt;&#x2F;text&gt;
  &lt;text x=&quot;225&quot; y=&quot;80&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;COLOR=red&lt;&#x2F;text&gt;
  &lt;text x=&quot;225&quot; y=&quot;100&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;dies on exit&lt;&#x2F;text&gt;
  &lt;!-- X through inheritance arrow going back --&gt;
&lt;p&gt;&lt;text x=&quot;152&quot; y=&quot;125&quot; fill=&quot;#C0392B&quot; font-size=&quot;18&quot; text-anchor=&quot;middle&quot;&gt;X&lt;&#x2F;text&gt;
&lt;text x=&quot;152&quot; y=&quot;142&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;no return&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Right side: source --&gt;
&lt;p&gt;&lt;text x=&quot;430&quot; y=&quot;25&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;source script.sh&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;340&quot; y=&quot;40&quot; width=&quot;180&quot; height=&quot;100&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;65&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Same shell process&lt;&#x2F;text&gt;
  &lt;rect x=&quot;360&quot; y=&quot;80&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;98&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;script runs HERE&lt;&#x2F;text&gt;
  &lt;text x=&quot;430&quot; y=&quot;115&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;COLOR=red persists&lt;&#x2F;text&gt;
  &lt;!-- Summary --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;180&quot; width=&quot;250&quot; height=&quot;80&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;200&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;bash script.sh&lt;&#x2F;text&gt;
  &lt;text x=&quot;155&quot; y=&quot;220&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;New process. Variable changes&lt;&#x2F;text&gt;
  &lt;text x=&quot;155&quot; y=&quot;235&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;are lost when script exits.&lt;&#x2F;text&gt;
  &lt;rect x=&quot;300&quot; y=&quot;180&quot; width=&quot;250&quot; height=&quot;80&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot;&#x2F;&gt;
  &lt;text x=&quot;425&quot; y=&quot;200&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;source script.sh&lt;&#x2F;text&gt;
  &lt;text x=&quot;425&quot; y=&quot;220&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Same process. Variable changes&lt;&#x2F;text&gt;
  &lt;text x=&quot;425&quot; y=&quot;235&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;persist in the current shell.&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr21c&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Running a script with &quot;bash script.sh&quot; creates a child process. Variables set inside it vanish when it exits. Sourcing with &quot;source script.sh&quot; (or &quot;. script.sh&quot;) executes the commands in your current shell, so changes stick.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;div class=&quot;remember&quot;&gt;
If you want a script to set variables in your current shell, source it. If you want a script&#x27;s variable changes to be isolated and temporary, run it normally. This is not a limitation -- it is a safety feature. Scripts cannot silently alter your working environment unless you explicitly allow it.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;practical-patterns&quot;&gt;Practical Patterns&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Add a directory to PATH persistently.&lt;&#x2F;strong&gt; Edit &lt;code&gt;~&#x2F;.bash_profile&lt;&#x2F;code&gt; (or &lt;code&gt;~&#x2F;.profile&lt;&#x2F;code&gt;) and add:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;export PATH=&amp;quot;$HOME&#x2F;.local&#x2F;bin:$PATH&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then either log out and back in, or source the file: &lt;code&gt;source ~&#x2F;.bash_profile&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Set a variable for development.&lt;&#x2F;strong&gt; Many programs read environment variables for configuration:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ export DATABASE_URL=&amp;quot;postgres:&#x2F;&#x2F;localhost&#x2F;mydb&amp;quot;
$ export DEBUG=1
$ .&#x2F;my-app
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Check if a variable is set.&lt;&#x2F;strong&gt; Use the &lt;code&gt;-z&lt;&#x2F;code&gt; test (we will use this more in Article 22):&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ if [ -z &amp;quot;$DATABASE_URL&amp;quot; ]; then echo &amp;quot;Not set&amp;quot;; fi
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Pass secrets without command-line arguments.&lt;&#x2F;strong&gt; Command-line arguments are visible in &lt;code&gt;ps&lt;&#x2F;code&gt; output. Environment variables are not (by default). This is why database passwords and API keys are typically passed as environment variables rather than flags.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-you-have-learned&quot;&gt;What You Have Learned&lt;&#x2F;h2&gt;
&lt;p&gt;Environment variables are key-value pairs carried by every process. The shell maintains both shell-only variables and exported environment variables. Only exported variables are inherited by child processes. Inheritance flows one way -- children cannot modify their parent&#x27;s environment. The startup files &lt;code&gt;~&#x2F;.bash_profile&lt;&#x2F;code&gt; and &lt;code&gt;~&#x2F;.bashrc&lt;&#x2F;code&gt; build your environment at login and shell startup. The &lt;code&gt;source&lt;&#x2F;code&gt; command executes a file in the current shell, which is the only way a script can modify the current shell&#x27;s variables.&lt;&#x2F;p&gt;
&lt;p&gt;The environment is the invisible layer of configuration that sits between the operating system and every program you run. Understanding it demystifies why things &quot;just work&quot; -- and, more importantly, why they sometimes do not.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;22-your-first-shell-script&#x2F;&quot;&gt;Your First Shell Script&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pipes and Redirection</title>
        <published>2025-01-24T00:00:00+00:00</published>
        <updated>2025-01-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/20-pipes-and-redirection/"/>
        <id>https://t34ch.tech/coldboot/articles/20-pipes-and-redirection/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/20-pipes-and-redirection/">&lt;p&gt;In the previous article, you learned that every process has three standard channels and that programs do not know or care where those channels actually lead. Now we put that design to work. The shell gives you simple syntax for rewiring those channels: send output to a file, read input from a file, or connect the output of one program directly to the input of another.&lt;&#x2F;p&gt;
&lt;p&gt;This is the mechanism that turns a collection of small, single-purpose programs into a powerful system. Each program does one thing. You combine them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;output-redirection-and&quot;&gt;Output Redirection: &amp;gt; and &amp;gt;&amp;gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;&amp;gt;&lt;&#x2F;code&gt; operator tells the shell to connect a program&#x27;s stdout to a file instead of the screen. The shell opens (or creates) the file, then sets file descriptor 1 to point at it before starting the program.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &amp;quot;first line&amp;quot; &amp;gt; output.txt
$ cat output.txt
first line
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the file already exists, &lt;code&gt;&amp;gt;&lt;&#x2F;code&gt; destroys its contents and starts fresh. This is called &lt;strong&gt;truncation&lt;&#x2F;strong&gt;. The old data is gone the moment the shell processes the &lt;code&gt;&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to add to an existing file instead of replacing it, use &lt;code&gt;&amp;gt;&amp;gt;&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &amp;quot;second line&amp;quot; &amp;gt;&amp;gt; output.txt
$ cat output.txt
first line
second line
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;gt;&amp;gt;&lt;&#x2F;code&gt; operator opens the file in &lt;strong&gt;append mode&lt;&#x2F;strong&gt;. New data is written after the existing contents. Nothing is deleted.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Redirection&lt;&#x2F;strong&gt;
The shell&#x27;s mechanism for changing where a process&#x27;s standard channels (stdin, stdout, stderr) connect. The operators &gt;, &gt;&gt;, &lt;, and 2&gt; rewire file descriptors before the program starts. The program itself is unaware that redirection has occurred.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 20.0 -- Output redirection with &gt; and &gt;&gt;&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Scenario 1: &gt; truncate --&gt;
&lt;p&gt;&lt;text x=&quot;20&quot; y=&quot;30&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; font-weight=&quot;bold&quot;&gt;echo &quot;hello&quot; &amp;gt; file.txt&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;20&quot; y=&quot;45&quot; width=&quot;120&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;70&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;echo&lt;&#x2F;text&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;65&quot; x2=&quot;220&quot; y2=&quot;65&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr20a)&quot;&#x2F;&gt;
  &lt;text x=&quot;180&quot; y=&quot;58&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;stdout&lt;&#x2F;text&gt;
  &lt;!-- File before: has content --&gt;
  &lt;rect x=&quot;230&quot; y=&quot;40&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;57&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;old content&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;52&quot; x2=&quot;360&quot; y2=&quot;72&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;80&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;replaced with &quot;hello&quot;&lt;&#x2F;text&gt;
  &lt;!-- Arrow showing truncation --&gt;
&lt;p&gt;&lt;text x=&quot;420&quot; y=&quot;65&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;TRUNCATED&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Scenario 2: &gt;&gt; append --&gt;
&lt;p&gt;&lt;text x=&quot;20&quot; y=&quot;140&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; font-weight=&quot;bold&quot;&gt;echo &quot;world&quot; &amp;gt;&amp;gt; file.txt&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;20&quot; y=&quot;155&quot; width=&quot;120&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;180&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;echo&lt;&#x2F;text&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;175&quot; x2=&quot;220&quot; y2=&quot;175&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr20a)&quot;&#x2F;&gt;
  &lt;text x=&quot;180&quot; y=&quot;168&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;stdout&lt;&#x2F;text&gt;
  &lt;!-- File: shows appended content --&gt;
  &lt;rect x=&quot;230&quot; y=&quot;150&quot; width=&quot;140&quot; height=&quot;60&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;170&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;hello&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;177&quot; x2=&quot;360&quot; y2=&quot;177&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;195&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;world&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;420&quot; y=&quot;180&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;APPENDED&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Summary --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;235&quot; width=&quot;220&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;150&quot; y=&quot;255&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&amp;gt;  creates or overwrites&lt;&#x2F;text&gt;
  &lt;rect x=&quot;300&quot; y=&quot;235&quot; width=&quot;220&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;255&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&amp;gt;&amp;gt;  creates or appends&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr20a&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The &gt; operator replaces the file&#x27;s contents (truncation). The &gt;&gt; operator adds to the end (append). Both create the file if it does not exist.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;div class=&quot;remember&quot;&gt;
The `&gt;` operator destroys existing file contents. This is the single most common way people accidentally delete data from the command line. If you are not sure whether you want to overwrite, use `&gt;&gt;` to append instead.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;redirecting-standard-error&quot;&gt;Redirecting Standard Error&lt;&#x2F;h2&gt;
&lt;p&gt;By default, &lt;code&gt;&amp;gt;&lt;&#x2F;code&gt; redirects file descriptor 1 (stdout). To redirect file descriptor 2 (stderr), prefix the &lt;code&gt;&amp;gt;&lt;&#x2F;code&gt; with the descriptor number:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls &#x2F;nonexistent 2&amp;gt; errors.txt
$ cat errors.txt
ls: cannot access &amp;#39;&#x2F;nonexistent&amp;#39;: No such file or directory
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;2&amp;gt;&lt;&#x2F;code&gt; syntax sends stderr to the file. Normal output still goes to the screen.&lt;&#x2F;p&gt;
&lt;p&gt;You can redirect both at the same time:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls &#x2F;home &#x2F;nonexistent &amp;gt; listing.txt 2&amp;gt; errors.txt
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now stdout goes to &lt;code&gt;listing.txt&lt;&#x2F;code&gt; and stderr goes to &lt;code&gt;errors.txt&lt;&#x2F;code&gt;. Clean separation.&lt;&#x2F;p&gt;
&lt;p&gt;If you want both stdout and stderr to go to the same file, the syntax is:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ command &amp;gt; all_output.txt 2&amp;gt;&amp;amp;1
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;2&amp;gt;&amp;amp;1&lt;&#x2F;code&gt; means &quot;redirect file descriptor 2 to wherever file descriptor 1 currently points.&quot; Since we already redirected fd 1 to &lt;code&gt;all_output.txt&lt;&#x2F;code&gt;, fd 2 follows it there.&lt;&#x2F;p&gt;
&lt;p&gt;Order matters here. The shell processes redirections left to right. If you reversed it -- &lt;code&gt;2&amp;gt;&amp;amp;1 &amp;gt; all_output.txt&lt;&#x2F;code&gt; -- stderr would go to the screen (where fd 1 was pointing at the time) and only stdout would go to the file.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: File descriptor duplication&lt;&#x2F;strong&gt;
The syntax 2&gt;&amp;1 tells the shell to make file descriptor 2 point to the same place as file descriptor 1. This is called &quot;duplicating&quot; a file descriptor. It is how you merge stderr into stdout (or vice versa).
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;input-redirection&quot;&gt;Input Redirection: &amp;lt;&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;&lt;&#x2F;code&gt; operator connects a file to a program&#x27;s stdin instead of the keyboard:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ sort &amp;lt; names.txt
Alice
Bob
Charlie
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;sort&lt;&#x2F;code&gt; program reads from file descriptor 0 as usual. It does not know that stdin has been rewired from the keyboard to a file. It just reads lines, sorts them, and writes the result to stdout.&lt;&#x2F;p&gt;
&lt;p&gt;Many programs accept a filename as an argument, so you can often achieve the same result with:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ sort names.txt
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The difference is subtle but real. When you use &lt;code&gt;&amp;lt;&lt;&#x2F;code&gt;, the shell opens the file and passes the file descriptor to the program. The program reads from stdin and has no idea a file is involved. When you pass the filename as an argument, the program opens the file itself.&lt;&#x2F;p&gt;
&lt;p&gt;In practice, the result is the same. But the &lt;code&gt;&amp;lt;&lt;&#x2F;code&gt; form matters when you are building pipelines or working with programs that only read from stdin.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-pipe&quot;&gt;The Pipe: |&lt;&#x2F;h2&gt;
&lt;p&gt;The pipe operator is the most powerful tool in the Unix shell. It connects the stdout of one program directly to the stdin of the next. No temporary files. No manual copying. The data flows directly from one process to another through a kernel buffer.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls &#x2F;usr&#x2F;bin | wc -l
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This command lists all files in &lt;code&gt;&#x2F;usr&#x2F;bin&lt;&#x2F;code&gt; and sends that list (via a pipe) to &lt;code&gt;wc -l&lt;&#x2F;code&gt;, which counts the number of lines. The result is the number of programs installed in that directory.&lt;&#x2F;p&gt;
&lt;p&gt;Here is what happens mechanically:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The shell creates a pipe -- a pair of connected file descriptors, one for reading and one for writing.&lt;&#x2F;li&gt;
&lt;li&gt;It forks two child processes.&lt;&#x2F;li&gt;
&lt;li&gt;In the first child, stdout (fd 1) is connected to the write end of the pipe, then &lt;code&gt;ls&lt;&#x2F;code&gt; is executed.&lt;&#x2F;li&gt;
&lt;li&gt;In the second child, stdin (fd 0) is connected to the read end of the pipe, then &lt;code&gt;wc&lt;&#x2F;code&gt; is executed.&lt;&#x2F;li&gt;
&lt;li&gt;Both programs run simultaneously. As &lt;code&gt;ls&lt;&#x2F;code&gt; writes data, &lt;code&gt;wc&lt;&#x2F;code&gt; reads it.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 20.1 -- Anatomy of a pipe&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 240&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;240&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Command text --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;ls &#x2F;usr&#x2F;bin | wc -l&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Process 1 --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;55&quot; width=&quot;160&quot; height=&quot;70&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;110&quot; y=&quot;80&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;ls &#x2F;usr&#x2F;bin&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;writes to fd 1&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;115&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;(pipe write end)&lt;&#x2F;text&gt;
  &lt;!-- Pipe --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;65&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;20&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;85&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;kernel pipe&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;4 KB buffer&lt;&#x2F;text&gt;
  &lt;!-- Arrows through pipe --&gt;
  &lt;line x1=&quot;190&quot; y1=&quot;90&quot; x2=&quot;220&quot; y2=&quot;90&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr20b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;90&quot; x2=&quot;390&quot; y2=&quot;90&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr20c)&quot;&#x2F;&gt;
  &lt;!-- Process 2 --&gt;
  &lt;rect x=&quot;390&quot; y=&quot;55&quot; width=&quot;160&quot; height=&quot;70&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;470&quot; y=&quot;80&quot; fill=&quot;#39D353&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;wc -l&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;reads from fd 0&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;115&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;(pipe read end)&lt;&#x2F;text&gt;
  &lt;!-- Data flow illustration --&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;160&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;ls output:&lt;&#x2F;text&gt;
&lt;text x=&quot;30&quot; y=&quot;175&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;bash&lt;&#x2F;text&gt;
&lt;text x=&quot;30&quot; y=&quot;190&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;cat&lt;&#x2F;text&gt;
&lt;text x=&quot;30&quot; y=&quot;205&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;chmod&lt;&#x2F;text&gt;
&lt;text x=&quot;30&quot; y=&quot;220&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;...&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Flow arrow --&gt;
  &lt;line x1=&quot;100&quot; y1=&quot;190&quot; x2=&quot;380&quot; y2=&quot;190&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot; marker-end=&quot;url(#arr20d)&quot;&#x2F;&gt;
  &lt;text x=&quot;240&quot; y=&quot;183&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;bytes flow through pipe&lt;&#x2F;text&gt;
  &lt;!-- wc result --&gt;
&lt;p&gt;&lt;text x=&quot;420&quot; y=&quot;175&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;wc output:&lt;&#x2F;text&gt;
&lt;text x=&quot;420&quot; y=&quot;195&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot;&gt;1847&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr20b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr20c&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr20d&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The shell creates a kernel pipe with a small buffer (typically 4 KB on Linux, though it can grow to 64 KB). The first program writes to it; the second reads from it. Both run concurrently.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The key insight is that both programs run at the same time. The pipe is not &quot;run the first command, save its output, then feed it to the second command.&quot; It is a live connection. If the pipe buffer fills up because the writer is faster than the reader, the writer is paused until the reader catches up. This is called &lt;strong&gt;backpressure&lt;&#x2F;strong&gt;, and it means pipes work efficiently even with large amounts of data.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;building-pipelines&quot;&gt;Building Pipelines&lt;&#x2F;h2&gt;
&lt;p&gt;You can chain as many pipes as you want:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ cat &#x2F;var&#x2F;log&#x2F;syslog | grep &amp;quot;error&amp;quot; | sort | uniq -c | sort -rn | head -10
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This pipeline:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Reads the system log&lt;&#x2F;li&gt;
&lt;li&gt;Filters for lines containing &quot;error&quot;&lt;&#x2F;li&gt;
&lt;li&gt;Sorts those lines alphabetically (so duplicates are adjacent)&lt;&#x2F;li&gt;
&lt;li&gt;Counts consecutive duplicate lines&lt;&#x2F;li&gt;
&lt;li&gt;Sorts by count, highest first&lt;&#x2F;li&gt;
&lt;li&gt;Shows only the top 10&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Six programs, each doing one small job, connected into a single data-processing chain. No temporary files. No programming language required.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 20.2 -- A six-stage pipeline&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Stage 1 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;30&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;70&quot; y=&quot;55&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;cat syslog&lt;&#x2F;text&gt;
  &lt;line x1=&quot;120&quot; y1=&quot;50&quot; x2=&quot;145&quot; y2=&quot;50&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr20e)&quot;&#x2F;&gt;
  &lt;text x=&quot;132&quot; y=&quot;44&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;|&lt;&#x2F;text&gt;
  &lt;!-- Stage 2 --&gt;
  &lt;rect x=&quot;150&quot; y=&quot;30&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;200&quot; y=&quot;55&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;grep error&lt;&#x2F;text&gt;
  &lt;line x1=&quot;250&quot; y1=&quot;50&quot; x2=&quot;275&quot; y2=&quot;50&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr20e)&quot;&#x2F;&gt;
  &lt;text x=&quot;262&quot; y=&quot;44&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;|&lt;&#x2F;text&gt;
  &lt;!-- Stage 3 --&gt;
  &lt;rect x=&quot;280&quot; y=&quot;30&quot; width=&quot;80&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;55&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;sort&lt;&#x2F;text&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;50&quot; x2=&quot;385&quot; y2=&quot;50&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr20e)&quot;&#x2F;&gt;
  &lt;text x=&quot;372&quot; y=&quot;44&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;|&lt;&#x2F;text&gt;
  &lt;!-- Stage 4 --&gt;
  &lt;rect x=&quot;390&quot; y=&quot;30&quot; width=&quot;80&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;55&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;uniq -c&lt;&#x2F;text&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;50&quot; x2=&quot;495&quot; y2=&quot;50&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr20e)&quot;&#x2F;&gt;
  &lt;text x=&quot;482&quot; y=&quot;44&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;|&lt;&#x2F;text&gt;
  &lt;!-- Stage 5 --&gt;
  &lt;rect x=&quot;500&quot; y=&quot;30&quot; width=&quot;60&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;530&quot; y=&quot;50&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;sort&lt;&#x2F;text&gt;
  &lt;text x=&quot;530&quot; y=&quot;62&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;-rn&lt;&#x2F;text&gt;
  &lt;!-- Line down to stage 6 --&gt;
  &lt;line x1=&quot;530&quot; y1=&quot;70&quot; x2=&quot;530&quot; y2=&quot;95&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;530&quot; y1=&quot;95&quot; x2=&quot;470&quot; y2=&quot;95&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr20f)&quot;&#x2F;&gt;
  &lt;!-- Stage 6 --&gt;
  &lt;rect x=&quot;390&quot; y=&quot;80&quot; width=&quot;80&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;102&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;head -10&lt;&#x2F;text&gt;
  &lt;!-- Data flow illustration --&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;140&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Data at each stage:&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;165&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;1. All 50,000 log lines&lt;&#x2F;text&gt;
&lt;rect x=&quot;250&quot; y=&quot;155&quot; width=&quot;200&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#FFD700&quot; fill-opacity=&quot;0.2&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;185&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;2. 340 lines with &quot;error&quot;&lt;&#x2F;text&gt;
&lt;rect x=&quot;250&quot; y=&quot;175&quot; width=&quot;30&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#00BFFF&quot; fill-opacity=&quot;0.3&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;205&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;3. 340 lines, sorted&lt;&#x2F;text&gt;
&lt;rect x=&quot;250&quot; y=&quot;195&quot; width=&quot;30&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#39D353&quot; fill-opacity=&quot;0.3&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;225&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;4. 85 unique lines with counts&lt;&#x2F;text&gt;
&lt;rect x=&quot;250&quot; y=&quot;215&quot; width=&quot;16&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#FF6600&quot; fill-opacity=&quot;0.3&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;245&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;5. 85 lines, sorted by count&lt;&#x2F;text&gt;
&lt;rect x=&quot;250&quot; y=&quot;235&quot; width=&quot;16&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot; fill-opacity=&quot;0.3&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;265&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;6. Top 10 lines&lt;&#x2F;text&gt;
&lt;rect x=&quot;250&quot; y=&quot;255&quot; width=&quot;4&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#FFD700&quot; fill-opacity=&quot;0.4&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;290&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Each stage reduces the data. The final output is tiny compared to the input.&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr20e&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr20f&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;0&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M8,0 L0,3 L8,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A six-stage pipeline progressively filters and transforms data. Each program runs simultaneously, connected by kernel pipes. 50,000 lines go in; 10 come out.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;div class=&quot;remember&quot;&gt;
The Unix philosophy is &quot;write programs that do one thing well, and connect them with pipes.&quot; This is not just a slogan. It is a practical engineering strategy that has worked for over fifty years. Small composable tools are easier to test, debug, and combine than large monolithic programs.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;combining-redirection-and-pipes&quot;&gt;Combining Redirection and Pipes&lt;&#x2F;h2&gt;
&lt;p&gt;You can use redirection and pipes together. Redirection affects a single program&#x27;s file descriptors; pipes connect programs to each other.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ grep &amp;quot;error&amp;quot; &amp;lt; input.log | sort &amp;gt; sorted_errors.txt
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This reads &lt;code&gt;input.log&lt;&#x2F;code&gt; into grep&#x27;s stdin, pipes grep&#x27;s stdout to sort, and redirects sort&#x27;s stdout to a file. Each piece works independently.&lt;&#x2F;p&gt;
&lt;p&gt;You can also discard unwanted output in a pipeline:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ find &#x2F; -name &amp;quot;*.conf&amp;quot; 2&amp;gt;&#x2F;dev&#x2F;null | head -20
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;find&lt;&#x2F;code&gt; command searches the entire filesystem, which generates many &quot;Permission denied&quot; errors on directories you cannot read. The &lt;code&gt;2&amp;gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt; throws those errors away. Only the successful results (stdout) flow through the pipe to &lt;code&gt;head&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;here-documents&quot;&gt;Here Documents&lt;&#x2F;h2&gt;
&lt;p&gt;Sometimes you want to feed multiple lines of text into a program&#x27;s stdin without creating a file first. A &lt;strong&gt;here document&lt;&#x2F;strong&gt; (or heredoc) lets you embed the input directly in the command:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ sort &amp;lt;&amp;lt;EOF
cherry
apple
banana
EOF
apple
banana
cherry
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;&amp;lt;EOF&lt;&#x2F;code&gt; tells the shell: &quot;read everything from the next line until you see a line containing only &lt;code&gt;EOF&lt;&#x2F;code&gt;, and feed it all into the program&#x27;s stdin.&quot; You can use any word in place of &lt;code&gt;EOF&lt;&#x2F;code&gt; -- it is just a delimiter.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Here document&lt;&#x2F;strong&gt;
A form of input redirection that allows you to embed multi-line text directly in a shell command. The syntax is &amp;lt;&amp;lt;WORD, where WORD is any delimiter. The shell reads input lines until it encounters a line containing only that delimiter, then feeds all the collected text to the command&#x27;s stdin.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-tee-command-splitting-a-stream&quot;&gt;The Tee Command: Splitting a Stream&lt;&#x2F;h2&gt;
&lt;p&gt;What if you want to save a pipeline&#x27;s intermediate output to a file while also passing it along to the next stage? The &lt;code&gt;tee&lt;&#x2F;code&gt; command reads from stdin, writes a copy to a file, and also writes to stdout:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls &#x2F;usr&#x2F;bin | tee listing.txt | wc -l
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This counts the files in &lt;code&gt;&#x2F;usr&#x2F;bin&lt;&#x2F;code&gt; (via &lt;code&gt;wc -l&lt;&#x2F;code&gt;) and also saves the full listing to &lt;code&gt;listing.txt&lt;&#x2F;code&gt;. The &lt;code&gt;tee&lt;&#x2F;code&gt; command is named after a T-shaped pipe fitting that splits a water flow into two directions.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 20.3 -- The tee command splits the data stream&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 200&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;200&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Input --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;70&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;70&quot; y=&quot;95&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;ls&lt;&#x2F;text&gt;
  &lt;line x1=&quot;120&quot; y1=&quot;90&quot; x2=&quot;180&quot; y2=&quot;90&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr20g)&quot;&#x2F;&gt;
  &lt;!-- Tee --&gt;
  &lt;rect x=&quot;185&quot; y=&quot;65&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;95&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;tee&lt;&#x2F;text&gt;
  &lt;!-- Output to file (downward) --&gt;
  &lt;line x1=&quot;235&quot; y1=&quot;115&quot; x2=&quot;235&quot; y2=&quot;160&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr20h)&quot;&#x2F;&gt;
  &lt;rect x=&quot;175&quot; y=&quot;162&quot; width=&quot;120&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;182&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;listing.txt&lt;&#x2F;text&gt;
  &lt;!-- Output to next program (rightward) --&gt;
  &lt;line x1=&quot;285&quot; y1=&quot;90&quot; x2=&quot;360&quot; y2=&quot;90&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr20i)&quot;&#x2F;&gt;
  &lt;rect x=&quot;365&quot; y=&quot;70&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;415&quot; y=&quot;95&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;wc -l&lt;&#x2F;text&gt;
  &lt;!-- Labels --&gt;
&lt;p&gt;&lt;text x=&quot;150&quot; y=&quot;80&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;stdin&lt;&#x2F;text&gt;
&lt;text x=&quot;260&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;copy to file&lt;&#x2F;text&gt;
&lt;text x=&quot;325&quot; y=&quot;82&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;stdout&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Result --&gt;
  &lt;line x1=&quot;465&quot; y1=&quot;90&quot; x2=&quot;520&quot; y2=&quot;90&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr20i)&quot;&#x2F;&gt;
  &lt;text x=&quot;540&quot; y=&quot;95&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;14&quot; font-weight=&quot;bold&quot;&gt;1847&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr20g&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr20h&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr20i&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The tee command acts like a T-junction in plumbing. Data flows in from the left. One copy goes down to a file. Another copy continues right to the next program in the pipeline.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;common-patterns&quot;&gt;Common Patterns&lt;&#x2F;h2&gt;
&lt;p&gt;Here are redirection and pipe patterns you will use constantly:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Save command output to a file:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ dmesg &amp;gt; boot_messages.txt
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Append to a log:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &amp;quot;$(date): backup complete&amp;quot; &amp;gt;&amp;gt; &#x2F;var&#x2F;log&#x2F;backup.log
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Discard errors:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ find &#x2F; -name &amp;quot;*.conf&amp;quot; 2&amp;gt;&#x2F;dev&#x2F;null
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Send both stdout and stderr to a file:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ make &amp;gt; build.log 2&amp;gt;&amp;amp;1
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Count lines in a filtered result:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ grep -r &amp;quot;TODO&amp;quot; src&#x2F; | wc -l
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Find the ten largest files:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ du -sh &#x2F;var&#x2F;* 2&amp;gt;&#x2F;dev&#x2F;null | sort -rh | head -10
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each of these combines the same small set of operators -- &lt;code&gt;&amp;gt;&lt;&#x2F;code&gt;, &lt;code&gt;&amp;gt;&amp;gt;&lt;&#x2F;code&gt;, &lt;code&gt;&amp;lt;&lt;&#x2F;code&gt;, &lt;code&gt;2&amp;gt;&lt;&#x2F;code&gt;, &lt;code&gt;|&lt;&#x2F;code&gt; -- in different ways. The syntax is minimal. The power comes from composition.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-you-have-learned&quot;&gt;What You Have Learned&lt;&#x2F;h2&gt;
&lt;p&gt;Output redirection with &lt;code&gt;&amp;gt;&lt;&#x2F;code&gt; sends stdout to a file (truncating it). Append redirection with &lt;code&gt;&amp;gt;&amp;gt;&lt;&#x2F;code&gt; adds to the end. Input redirection with &lt;code&gt;&amp;lt;&lt;&#x2F;code&gt; feeds a file into stdin. The &lt;code&gt;2&amp;gt;&lt;&#x2F;code&gt; form redirects stderr specifically, and &lt;code&gt;2&amp;gt;&amp;amp;1&lt;&#x2F;code&gt; merges stderr into stdout. The pipe operator &lt;code&gt;|&lt;&#x2F;code&gt; connects one program&#x27;s stdout to the next program&#x27;s stdin, allowing you to build multi-stage data processing pipelines. The &lt;code&gt;tee&lt;&#x2F;code&gt; command lets you save a copy of data mid-pipeline.&lt;&#x2F;p&gt;
&lt;p&gt;These operators are the glue that holds the Unix tool ecosystem together. Small programs, each doing one thing, connected into arbitrarily complex workflows.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;21-the-environment&#x2F;&quot;&gt;The Environment&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Standard I&#x2F;O</title>
        <published>2025-01-23T00:00:00+00:00</published>
        <updated>2025-01-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/19-standard-io/"/>
        <id>https://t34ch.tech/coldboot/articles/19-standard-io/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/19-standard-io/">&lt;p&gt;Every program needs to communicate. It needs to receive input, produce output, and report problems. Unix solved this decades ago with an elegant design: every process is born with three open communication channels. No setup required. No configuration files. They are just there.&lt;&#x2F;p&gt;
&lt;p&gt;These three channels are called &lt;strong&gt;standard input&lt;&#x2F;strong&gt;, &lt;strong&gt;standard output&lt;&#x2F;strong&gt;, and &lt;strong&gt;standard error&lt;&#x2F;strong&gt;. Together, they form the foundation of how every command-line program talks to the world.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;three-channels-always&quot;&gt;Three Channels, Always&lt;&#x2F;h2&gt;
&lt;p&gt;Imagine a factory machine. It has a conveyor belt feeding raw materials in one side. It has a second conveyor belt carrying finished products out the other side. And it has an alarm buzzer that goes off when something goes wrong. The raw materials belt is standard input. The finished products belt is standard output. The alarm is standard error.&lt;&#x2F;p&gt;
&lt;p&gt;Every process on a Unix system starts with exactly these three channels open:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Standard input (stdin)&lt;&#x2F;strong&gt; -- where the program reads incoming data&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Standard output (stdout)&lt;&#x2F;strong&gt; -- where the program writes its normal results&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Standard error (stderr)&lt;&#x2F;strong&gt; -- where the program writes error messages and diagnostics&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;By default, stdin is connected to your keyboard (through the terminal), and both stdout and stderr are connected to your screen. But as we will see in the next article, these connections can be rewired.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Standard I&#x2F;O&lt;&#x2F;strong&gt;
The three default communication channels that every Unix process receives at birth: standard input (stdin) for reading data, standard output (stdout) for writing results, and standard error (stderr) for writing error messages. They are the universal interface between programs and the outside world.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 19.0 -- The three standard channels&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 240&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;240&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Keyboard --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;85&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;75&quot; y=&quot;110&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Keyboard&lt;&#x2F;text&gt;
  &lt;!-- Process box --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;50&quot; width=&quot;160&quot; height=&quot;140&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;85&quot; fill=&quot;#FFD700&quot; font-size=&quot;14&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Process&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;105&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;(e.g., grep)&lt;&#x2F;text&gt;
  &lt;!-- Screen --&gt;
  &lt;rect x=&quot;450&quot; y=&quot;45&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;505&quot; y=&quot;70&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Screen&lt;&#x2F;text&gt;
  &lt;rect x=&quot;450&quot; y=&quot;155&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;505&quot; y=&quot;180&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Screen&lt;&#x2F;text&gt;
  &lt;!-- stdin arrow --&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;105&quot; x2=&quot;210&quot; y2=&quot;105&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr19a)&quot;&#x2F;&gt;
  &lt;text x=&quot;170&quot; y=&quot;98&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;stdin&lt;&#x2F;text&gt;
  &lt;!-- stdout arrow --&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;80&quot; x2=&quot;450&quot; y2=&quot;65&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr19b)&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;60&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;stdout&lt;&#x2F;text&gt;
  &lt;!-- stderr arrow --&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;160&quot; x2=&quot;450&quot; y2=&quot;175&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr19c)&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;185&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;stderr&lt;&#x2F;text&gt;
  &lt;!-- File descriptor labels --&gt;
&lt;p&gt;&lt;text x=&quot;215&quot; y=&quot;140&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;fd 0&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;140&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;fd 1&lt;&#x2F;text&gt;
&lt;text x=&quot;355&quot; y=&quot;140&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;fd 2&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Legend --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;225&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Default connections: keyboard feeds in, screen receives both outputs&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr19a&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr19b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr19c&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Every process starts with three channels. By default, stdin reads from the keyboard and both stdout and stderr write to the screen. The numbers 0, 1, and 2 are file descriptors -- the kernel&#x27;s internal names for these channels.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;file-descriptors-the-kernel-s-numbering-system&quot;&gt;File Descriptors: The Kernel&#x27;s Numbering System&lt;&#x2F;h2&gt;
&lt;p&gt;The kernel does not think in terms of names like &quot;stdin&quot; and &quot;stdout.&quot; It uses numbers. Each open channel in a process gets a sequential integer called a &lt;strong&gt;file descriptor&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The first three are always assigned the same way:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;0&lt;&#x2F;strong&gt; -- standard input&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;1&lt;&#x2F;strong&gt; -- standard output&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;2&lt;&#x2F;strong&gt; -- standard error&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If a process opens additional files, they get the next available numbers: 3, 4, 5, and so on. But 0, 1, and 2 are reserved by convention, and every program assumes they are there.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: File descriptor&lt;&#x2F;strong&gt;
A small non-negative integer that the kernel assigns to each open file, socket, pipe, or I&#x2F;O channel within a process. File descriptors 0, 1, and 2 are pre-assigned to stdin, stdout, and stderr. Every read or write operation in a Unix program ultimately references a file descriptor number.
&lt;&#x2F;div&gt;
&lt;p&gt;This numbering system is important because it is how you target specific channels when redirecting. Want to redirect just error messages to a file while keeping normal output on screen? You need to reference file descriptor 2 specifically. We will do exactly that in the next article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;standard-output-where-results-go&quot;&gt;Standard Output: Where Results Go&lt;&#x2F;h2&gt;
&lt;p&gt;When a program wants to display results, it writes to stdout (file descriptor 1). The &lt;code&gt;echo&lt;&#x2F;code&gt; command writes its arguments to stdout. The &lt;code&gt;ls&lt;&#x2F;code&gt; command writes its file listing to stdout. The &lt;code&gt;cat&lt;&#x2F;code&gt; command reads files and writes their contents to stdout.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &amp;quot;Hello, world&amp;quot;
Hello, world
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The text &quot;Hello, world&quot; went to stdout, which was connected to your terminal, which displayed it on screen. Simple.&lt;&#x2F;p&gt;
&lt;p&gt;Here is the critical thing: the program does not know or care where stdout actually goes. It just writes bytes to file descriptor 1. Whether those bytes end up on a screen, in a file, or fed into another program is decided by whoever set up the file descriptors before the program started. Usually, that is the shell.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 19.1 -- stdout does not know its destination&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Program box --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;100&quot; width=&quot;150&quot; height=&quot;60&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;105&quot; y=&quot;125&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;echo&lt;&#x2F;text&gt;
  &lt;text x=&quot;105&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;writes to fd 1&lt;&#x2F;text&gt;
  &lt;!-- Arrow out --&gt;
  &lt;line x1=&quot;180&quot; y1=&quot;130&quot; x2=&quot;240&quot; y2=&quot;130&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr19d)&quot;&#x2F;&gt;
  &lt;text x=&quot;210&quot; y=&quot;123&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;stdout&lt;&#x2F;text&gt;
  &lt;!-- Branch point --&gt;
  &lt;circle cx=&quot;250&quot; cy=&quot;130&quot; r=&quot;5&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;!-- Scenario 1: Screen --&gt;
  &lt;line x1=&quot;255&quot; y1=&quot;130&quot; x2=&quot;350&quot; y2=&quot;50&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;rect x=&quot;360&quot; y=&quot;30&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;52&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Screen&lt;&#x2F;text&gt;
  &lt;text x=&quot;500&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;default&lt;&#x2F;text&gt;
  &lt;!-- Scenario 2: File --&gt;
  &lt;line x1=&quot;255&quot; y1=&quot;130&quot; x2=&quot;350&quot; y2=&quot;130&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;rect x=&quot;360&quot; y=&quot;112&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;134&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;File&lt;&#x2F;text&gt;
  &lt;text x=&quot;500&quot; y=&quot;134&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;&amp;gt; out.txt&lt;&#x2F;text&gt;
  &lt;!-- Scenario 3: Another program --&gt;
  &lt;line x1=&quot;255&quot; y1=&quot;130&quot; x2=&quot;350&quot; y2=&quot;210&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;rect x=&quot;360&quot; y=&quot;192&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;214&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Next program&lt;&#x2F;text&gt;
  &lt;text x=&quot;500&quot; y=&quot;214&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;| grep&lt;&#x2F;text&gt;
  &lt;!-- Note --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;265&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;The program writes to fd 1 the same way in all three cases.&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;278&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Only the shell knows where the bytes actually go.&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr19d&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The echo command writes bytes to file descriptor 1 without knowing where they end up. The shell can connect that file descriptor to the screen (default), a file, or the input of another program.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;div class=&quot;remember&quot;&gt;
Programs do not write &quot;to the screen&quot; or &quot;to a file.&quot; They write to a file descriptor. Where that file descriptor points is decided externally, usually by the shell. This separation is what makes pipes and redirection possible.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;standard-error-a-separate-channel-for-problems&quot;&gt;Standard Error: A Separate Channel for Problems&lt;&#x2F;h2&gt;
&lt;p&gt;Why do error messages need their own channel? Consider this situation: you run a program and send its output to a file. The program encounters an error halfway through. If the error message goes to stdout, it ends up mixed into the output file, corrupting the data. If the error message goes to stderr, it still appears on your screen even though stdout was redirected elsewhere.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls &#x2F;home &#x2F;nonexistent
&#x2F;home:
user1  user2

ls: cannot access &amp;#39;&#x2F;nonexistent&amp;#39;: No such file or directory
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example, the file listing goes to stdout and the error message goes to stderr. Both happen to be connected to your screen, so you see them interleaved. But if you redirect stdout to a file, the error still shows up on your terminal:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls &#x2F;home &#x2F;nonexistent &amp;gt; listing.txt
ls: cannot access &amp;#39;&#x2F;nonexistent&amp;#39;: No such file or directory
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The file &lt;code&gt;listing.txt&lt;&#x2F;code&gt; contains the directory listing, clean and uncorrupted. The error message appeared on screen because stderr was not redirected -- only stdout was.&lt;&#x2F;p&gt;
&lt;p&gt;This is why stderr exists: to keep error messages out of the data stream.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;standard-input-how-programs-read&quot;&gt;Standard Input: How Programs Read&lt;&#x2F;h2&gt;
&lt;p&gt;Most interactive programs read from stdin (file descriptor 0). By default, this is connected to your keyboard through the terminal.&lt;&#x2F;p&gt;
&lt;p&gt;When you run &lt;code&gt;cat&lt;&#x2F;code&gt; with no arguments, it reads from stdin:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ cat
Hello
Hello
World
World
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each line you type is echoed back because &lt;code&gt;cat&lt;&#x2F;code&gt; reads stdin and writes to stdout. Press Ctrl+D to signal &quot;end of input&quot; -- this sends an EOF (end-of-file) marker that tells the program there is nothing more to read.&lt;&#x2F;p&gt;
&lt;p&gt;Programs that process data -- like &lt;code&gt;sort&lt;&#x2F;code&gt;, &lt;code&gt;grep&lt;&#x2F;code&gt;, &lt;code&gt;wc&lt;&#x2F;code&gt; -- can all read from stdin when given no filename argument. This is what makes pipes work, but we are getting ahead of ourselves.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 19.2 -- stdin sources&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 240&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;240&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Sources on the left --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;20&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;42&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Keyboard&lt;&#x2F;text&gt;
  &lt;text x=&quot;190&quot; y=&quot;42&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;default&lt;&#x2F;text&gt;
  &lt;rect x=&quot;30&quot; y=&quot;70&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;92&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;File&lt;&#x2F;text&gt;
  &lt;text x=&quot;190&quot; y=&quot;92&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;&amp;lt; data.txt&lt;&#x2F;text&gt;
  &lt;rect x=&quot;30&quot; y=&quot;120&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;142&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Pipe from program&lt;&#x2F;text&gt;
  &lt;text x=&quot;190&quot; y=&quot;142&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;echo hi |&lt;&#x2F;text&gt;
  &lt;!-- Converge point --&gt;
  &lt;line x1=&quot;170&quot; y1=&quot;37&quot; x2=&quot;280&quot; y2=&quot;105&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;170&quot; y1=&quot;87&quot; x2=&quot;280&quot; y2=&quot;105&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;170&quot; y1=&quot;137&quot; x2=&quot;280&quot; y2=&quot;105&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;!-- fd 0 label --&gt;
  &lt;circle cx=&quot;290&quot; cy=&quot;105&quot; r=&quot;18&quot; fill=&quot;none&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;110&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;fd 0&lt;&#x2F;text&gt;
  &lt;!-- Arrow to process --&gt;
  &lt;line x1=&quot;308&quot; y1=&quot;105&quot; x2=&quot;360&quot; y2=&quot;105&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr19e)&quot;&#x2F;&gt;
  &lt;!-- Process --&gt;
  &lt;rect x=&quot;370&quot; y=&quot;80&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;450&quot; y=&quot;105&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;sort&lt;&#x2F;text&gt;
  &lt;text x=&quot;450&quot; y=&quot;118&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;reads fd 0&lt;&#x2F;text&gt;
  &lt;!-- Note --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;190&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Only one source is connected at a time.&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;205&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;The program reads from fd 0 the same way regardless of source.&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr19e&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;File descriptor 0 (stdin) can be connected to the keyboard, a file, or the output of another program. The receiving program reads from fd 0 identically in all three cases.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-dev-null-black-hole&quot;&gt;The &#x2F;dev&#x2F;null Black Hole&lt;&#x2F;h2&gt;
&lt;p&gt;Sometimes you want to throw output away entirely. Maybe a program prints progress messages you do not care about. Maybe you want to run a command silently.&lt;&#x2F;p&gt;
&lt;p&gt;Unix provides a special file for this: &lt;code&gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt;. It is a device file that accepts any data written to it and discards it immediately. Reading from it immediately returns end-of-file.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo &amp;quot;This disappears&amp;quot; &amp;gt; &#x2F;dev&#x2F;null
$ ls &#x2F;nonexistent 2&amp;gt; &#x2F;dev&#x2F;null
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first line sends stdout to &lt;code&gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt; -- the text vanishes. The second line sends stderr to &lt;code&gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt; -- the error message is suppressed. (The &lt;code&gt;2&amp;gt;&lt;&#x2F;code&gt; syntax means &quot;redirect file descriptor 2.&quot; We will cover this syntax fully in the next article.)&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: &#x2F;dev&#x2F;null&lt;&#x2F;strong&gt;
A special device file that discards all data written to it and returns end-of-file on reads. It is the Unix &quot;black hole&quot; -- useful for silencing unwanted output or error messages. The name literally means the &quot;null device.&quot;
&lt;&#x2F;div&gt;
&lt;p&gt;Think of &lt;code&gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt; as a trash can with no bottom. You can throw anything in. Nothing ever comes back out. Nothing accumulates. It is bottomless and always empty.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;everything-is-a-file-descriptor&quot;&gt;Everything Is a File (Descriptor)&lt;&#x2F;h2&gt;
&lt;p&gt;One of the defining ideas in Unix is that I&#x2F;O is uniform. Whether a program is reading from a keyboard, a file on disk, a network socket, or a pipe from another program, it uses the same system calls: &lt;code&gt;read()&lt;&#x2F;code&gt; and &lt;code&gt;write()&lt;&#x2F;code&gt;, operating on file descriptors.&lt;&#x2F;p&gt;
&lt;p&gt;This is why the standard channels are called &quot;file&quot; descriptors even though stdin often comes from a keyboard. The kernel presents all I&#x2F;O sources through the same interface. A program that reads from file descriptor 0 does not know -- and does not need to know -- whether it is reading keystrokes, file contents, or output from another program.&lt;&#x2F;p&gt;
&lt;p&gt;This uniformity is not an accident. It is a deliberate design choice that makes it trivial to compose programs. If every program reads from stdin and writes to stdout using the same interface, then any program&#x27;s output can be connected to any other program&#x27;s input. No special adapters. No format conversion. Just bytes flowing through file descriptors.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The power of standard I&#x2F;O comes from its uniformity. Every program reads and writes the same way, regardless of what is on the other end of the file descriptor. This uniformity is what makes the entire Unix pipeline model possible.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 19.3 -- Uniform I&#x2F;O through file descriptors&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Central column: system calls --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Kernel System Call Interface&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;220&quot; y=&quot;40&quot; width=&quot;140&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;60&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;read(fd, buf, n)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;220&quot; y=&quot;80&quot; width=&quot;140&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;100&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;write(fd, buf, n)&lt;&#x2F;text&gt;
  &lt;!-- Left side: what the program sees --&gt;
&lt;p&gt;&lt;text x=&quot;100&quot; y=&quot;140&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Program sees:&lt;&#x2F;text&gt;
&lt;text x=&quot;100&quot; y=&quot;160&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&quot;just a number&quot;&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;50&quot; y=&quot;175&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;195&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;fd 0&lt;&#x2F;text&gt;
  &lt;!-- Right side: what it could be --&gt;
&lt;p&gt;&lt;text x=&quot;440&quot; y=&quot;140&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Could be any of:&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;370&quot; y=&quot;155&quot; width=&quot;160&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;450&quot; y=&quot;172&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Terminal (keyboard)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;370&quot; y=&quot;185&quot; width=&quot;160&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;450&quot; y=&quot;202&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Regular file on disk&lt;&#x2F;text&gt;
  &lt;rect x=&quot;370&quot; y=&quot;215&quot; width=&quot;160&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;450&quot; y=&quot;232&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Pipe from another program&lt;&#x2F;text&gt;
  &lt;rect x=&quot;370&quot; y=&quot;245&quot; width=&quot;160&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;450&quot; y=&quot;262&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Network socket&lt;&#x2F;text&gt;
  &lt;!-- Connecting lines --&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;190&quot; x2=&quot;220&quot; y2=&quot;55&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;55&quot; x2=&quot;370&quot; y2=&quot;167&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;55&quot; x2=&quot;370&quot; y2=&quot;197&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;55&quot; x2=&quot;370&quot; y2=&quot;227&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;55&quot; x2=&quot;370&quot; y2=&quot;257&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;290&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Same read()&#x2F;write() calls work on any type of file descriptor.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A program calls read() and write() on file descriptor numbers without knowing what type of resource is on the other end. The kernel handles the translation between the uniform interface and the actual device or file.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;seeing-file-descriptors-in-action&quot;&gt;Seeing File Descriptors in Action&lt;&#x2F;h2&gt;
&lt;p&gt;You can inspect the file descriptors of a running process. Every process has a directory in &lt;code&gt;&#x2F;proc&lt;&#x2F;code&gt; that lists its open file descriptors:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls -l &#x2F;proc&#x2F;self&#x2F;fd
lrwx------ 1 user user 64 Jan 23 10:00 0 -&amp;gt; &#x2F;dev&#x2F;pts&#x2F;0
lrwx------ 1 user user 64 Jan 23 10:00 1 -&amp;gt; &#x2F;dev&#x2F;pts&#x2F;0
lrwx------ 1 user user 64 Jan 23 10:00 2 -&amp;gt; &#x2F;dev&#x2F;pts&#x2F;0
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;&#x2F;proc&#x2F;self&lt;&#x2F;code&gt; directory always refers to the currently running process. Here, all three standard file descriptors point to &lt;code&gt;&#x2F;dev&#x2F;pts&#x2F;0&lt;&#x2F;code&gt;, which is a pseudo-terminal device. That is the terminal you are typing in.&lt;&#x2F;p&gt;
&lt;p&gt;If you redirect stdout to a file and check again, you will see file descriptor 1 pointing to that file instead of the terminal.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-you-have-learned&quot;&gt;What You Have Learned&lt;&#x2F;h2&gt;
&lt;p&gt;Every Unix process starts with three open file descriptors: stdin (0) for reading input, stdout (1) for writing results, and stderr (2) for writing errors. Programs interact with these channels through uniform read and write system calls without knowing what is on the other end. Standard error exists as a separate channel so that error messages do not contaminate the data stream. The special file &lt;code&gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt; discards anything written to it.&lt;&#x2F;p&gt;
&lt;p&gt;This system of standard channels is not just a convenience. It is the architectural foundation that makes the next topic possible: connecting programs together with pipes and redirection.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;20-pipes-and-redirection&#x2F;&quot;&gt;Pipes and Redirection&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>What a Shell Actually Is</title>
        <published>2025-01-22T00:00:00+00:00</published>
        <updated>2025-01-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/18-what-a-shell-actually-is/"/>
        <id>https://t34ch.tech/coldboot/articles/18-what-a-shell-actually-is/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/18-what-a-shell-actually-is/">&lt;p&gt;You have been typing commands into a terminal for the last few articles. You pressed keys, text appeared, programs ran. But what exactly was reading those commands? What was deciding which program to start, and how?&lt;&#x2F;p&gt;
&lt;p&gt;The answer is the &lt;strong&gt;shell&lt;&#x2F;strong&gt;. It is not the terminal. It is not the window on your screen. It is a separate, ordinary program that happens to be very good at one thing: taking text commands from a human and turning them into running processes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-terminal-is-not-the-shell&quot;&gt;The Terminal Is Not the Shell&lt;&#x2F;h2&gt;
&lt;p&gt;Think of a restaurant. The terminal is the dining room -- the table, the chair, the menu. The shell is the waiter. You tell the waiter what you want. The waiter carries your order to the kitchen. The kitchen does the actual cooking.&lt;&#x2F;p&gt;
&lt;p&gt;The terminal handles input and output. It draws characters on screen. It captures your keystrokes. But it does not know what &lt;code&gt;ls&lt;&#x2F;code&gt; means. It does not know how to start a program. It is just a conduit.&lt;&#x2F;p&gt;
&lt;p&gt;The shell is the program running inside that terminal. It prints the prompt. It reads the line you type. It figures out what you meant. It asks the kernel to run the right program. When the program finishes, the shell prints the next prompt.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Shell&lt;&#x2F;strong&gt;
A command-line interpreter -- a program that reads text commands, parses them, and executes them by asking the kernel to create new processes. It is called a &quot;shell&quot; because it wraps around the kernel, forming the outer layer that humans interact with.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 18.0 -- Terminal vs. shell vs. kernel&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 270&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;270&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Terminal box --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;20&quot; width=&quot;160&quot; height=&quot;220&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;50&quot; fill=&quot;#00BFFF&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;TERMINAL&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;75&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;draws characters&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;90&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;captures keystrokes&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;105&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;displays output&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;120&quot; width=&quot;120&quot; height=&quot;100&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;148&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;SHELL&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;170&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;parses commands&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;185&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;looks up programs&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;200&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;manages jobs&lt;&#x2F;text&gt;
  &lt;!-- Arrow to kernel --&gt;
  &lt;line x1=&quot;160&quot; y1=&quot;170&quot; x2=&quot;260&quot; y2=&quot;170&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow18)&quot;&#x2F;&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrow18&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
  &lt;!-- Kernel box --&gt;
  &lt;rect x=&quot;270&quot; y=&quot;80&quot; width=&quot;140&quot; height=&quot;180&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;340&quot; y=&quot;110&quot; fill=&quot;#FF6600&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;KERNEL&lt;&#x2F;text&gt;
  &lt;text x=&quot;340&quot; y=&quot;135&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;creates processes&lt;&#x2F;text&gt;
  &lt;text x=&quot;340&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;manages memory&lt;&#x2F;text&gt;
  &lt;text x=&quot;340&quot; y=&quot;165&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;schedules CPU&lt;&#x2F;text&gt;
  &lt;text x=&quot;340&quot; y=&quot;180&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;handles I&#x2F;O&lt;&#x2F;text&gt;
  &lt;!-- Arrow to programs --&gt;
  &lt;line x1=&quot;410&quot; y1=&quot;170&quot; x2=&quot;440&quot; y2=&quot;170&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow18b)&quot;&#x2F;&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrow18b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
  &lt;!-- Programs --&gt;
  &lt;rect x=&quot;450&quot; y=&quot;90&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;505&quot; y=&quot;115&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;ls&lt;&#x2F;text&gt;
  &lt;rect x=&quot;450&quot; y=&quot;140&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;505&quot; y=&quot;165&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;grep&lt;&#x2F;text&gt;
  &lt;rect x=&quot;450&quot; y=&quot;190&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;505&quot; y=&quot;215&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;python3&lt;&#x2F;text&gt;
  &lt;!-- Human --&gt;
&lt;p&gt;&lt;text x=&quot;100&quot; y=&quot;255&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;YOU TYPE HERE&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The terminal displays text and captures keystrokes. The shell interprets commands. The kernel creates and manages the actual programs that do the work.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;You can prove this separation yourself. Open a terminal and type &lt;code&gt;echo $SHELL&lt;&#x2F;code&gt;. It will print something like &lt;code&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt; or &lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;zsh&lt;&#x2F;code&gt;. That is the path to a real file on disk -- the shell binary. You can even run a different shell inside your current one by typing its name, like &lt;code&gt;sh&lt;&#x2F;code&gt; or &lt;code&gt;zsh&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-happens-when-you-type-a-command&quot;&gt;What Happens When You Type a Command&lt;&#x2F;h2&gt;
&lt;p&gt;You type &lt;code&gt;ls -l &#x2F;tmp&lt;&#x2F;code&gt; and press Enter. Here is exactly what the shell does:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Read.&lt;&#x2F;strong&gt; The shell reads the entire line of text from standard input.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Parse.&lt;&#x2F;strong&gt; It splits the line into tokens. The first token is the command name: &lt;code&gt;ls&lt;&#x2F;code&gt;. The remaining tokens are arguments: &lt;code&gt;-l&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Find.&lt;&#x2F;strong&gt; The shell needs to locate the program called &lt;code&gt;ls&lt;&#x2F;code&gt;. It searches a list of directories, one by one, looking for an executable file with that name. This list is the PATH variable, and we will cover it in detail in Article 21.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Execute.&lt;&#x2F;strong&gt; The shell calls &lt;code&gt;fork()&lt;&#x2F;code&gt; to create a copy of itself, then the copy calls &lt;code&gt;exec()&lt;&#x2F;code&gt; to replace itself with the &lt;code&gt;ls&lt;&#x2F;code&gt; program. The original shell waits for &lt;code&gt;ls&lt;&#x2F;code&gt; to finish.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Wait.&lt;&#x2F;strong&gt; When &lt;code&gt;ls&lt;&#x2F;code&gt; exits, the shell collects its exit status -- a number that indicates success or failure. Then it prints the next prompt and goes back to Step 1.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 18.1 -- The shell&#x27;s read-eval-execute loop&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 320&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;320&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Step boxes arranged in a loop --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;20&quot; width=&quot;180&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;45&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;1. Read line&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;60&quot; x2=&quot;290&quot; y2=&quot;80&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arrowG18)&quot;&#x2F;&gt;
  &lt;rect x=&quot;200&quot; y=&quot;80&quot; width=&quot;180&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;105&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;2. Parse tokens&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;120&quot; x2=&quot;290&quot; y2=&quot;140&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arrowG18)&quot;&#x2F;&gt;
  &lt;rect x=&quot;200&quot; y=&quot;140&quot; width=&quot;180&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;165&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;3. Find program&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;180&quot; x2=&quot;290&quot; y2=&quot;200&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arrowG18)&quot;&#x2F;&gt;
  &lt;rect x=&quot;200&quot; y=&quot;200&quot; width=&quot;180&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;225&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;4. fork() + exec()&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;240&quot; x2=&quot;290&quot; y2=&quot;260&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arrowG18)&quot;&#x2F;&gt;
  &lt;rect x=&quot;200&quot; y=&quot;260&quot; width=&quot;180&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;285&quot; fill=&quot;#C0392B&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;5. Wait for exit&lt;&#x2F;text&gt;
  &lt;!-- Loop-back arrow --&gt;
  &lt;line x1=&quot;200&quot; y1=&quot;280&quot; x2=&quot;140&quot; y2=&quot;280&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;280&quot; x2=&quot;140&quot; y2=&quot;40&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;40&quot; x2=&quot;200&quot; y2=&quot;40&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arrowG18)&quot;&#x2F;&gt;
  &lt;text x=&quot;125&quot; y=&quot;165&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;loop&lt;&#x2F;text&gt;
  &lt;!-- Prompt indicator --&gt;
&lt;p&gt;&lt;text x=&quot;440&quot; y=&quot;45&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;$ ls -l &#x2F;tmp&lt;&#x2F;text&gt;
&lt;text x=&quot;440&quot; y=&quot;105&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;[&quot;ls&quot;,&quot;-l&quot;,&quot;&#x2F;tmp&quot;]&lt;&#x2F;text&gt;
&lt;text x=&quot;440&quot; y=&quot;165&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;&#x2F;usr&#x2F;bin&#x2F;ls&lt;&#x2F;text&gt;
&lt;text x=&quot;440&quot; y=&quot;225&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;PID 4821 running&lt;&#x2F;text&gt;
&lt;text x=&quot;440&quot; y=&quot;285&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;exit status: 0&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrowG18&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The shell runs in an infinite loop: read a command, parse it, find the program, execute it, wait for it to finish, then repeat. This loop is sometimes called the REPL -- read, evaluate, print, loop.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;This loop is the core of every shell. Everything else -- variables, conditionals, scripting -- is built on top of this basic cycle.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The shell is a loop. It reads a line, figures out what program to run, asks the kernel to run it, waits for it to finish, and then reads the next line. That is the fundamental operation, and it never changes.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;built-in-commands-vs-external-programs&quot;&gt;Built-in Commands vs. External Programs&lt;&#x2F;h2&gt;
&lt;p&gt;Not every command you type launches a separate program. Some commands are built into the shell itself.&lt;&#x2F;p&gt;
&lt;p&gt;Consider &lt;code&gt;cd &#x2F;tmp&lt;&#x2F;code&gt;. If the shell started a new process, changed that process&#x27;s working directory, and then that process exited -- well, the shell&#x27;s own working directory would be unchanged. The child process&#x27;s directory change would die with it. So &lt;code&gt;cd&lt;&#x2F;code&gt; has to be handled inside the shell itself, without forking a new process.&lt;&#x2F;p&gt;
&lt;p&gt;These are called &lt;strong&gt;built-in commands&lt;&#x2F;strong&gt; (or just &lt;strong&gt;builtins&lt;&#x2F;strong&gt;). Common builtins include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cd&lt;&#x2F;code&gt; -- change the shell&#x27;s working directory&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;echo&lt;&#x2F;code&gt; -- print text (also exists as an external program)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;export&lt;&#x2F;code&gt; -- set environment variables&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;exit&lt;&#x2F;code&gt; -- terminate the shell&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;type&lt;&#x2F;code&gt; -- tell you whether a command is a builtin or an external program&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can check any command with &lt;code&gt;type&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ type cd
cd is a shell builtin
$ type ls
ls is &#x2F;usr&#x2F;bin&#x2F;ls
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;External programs are separate executable files stored somewhere on disk. When you run &lt;code&gt;ls&lt;&#x2F;code&gt;, the shell finds &lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;ls&lt;&#x2F;code&gt;, creates a new process, and runs that file. When you run &lt;code&gt;cd&lt;&#x2F;code&gt;, the shell handles it internally and no new process is created.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Built-in command&lt;&#x2F;strong&gt;
A command that the shell executes directly, without creating a new process. Built-ins exist because certain operations -- like changing the working directory or setting variables -- must modify the shell&#x27;s own state, which a child process cannot do.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;how-the-shell-finds-programs-path&quot;&gt;How the Shell Finds Programs: PATH&lt;&#x2F;h2&gt;
&lt;p&gt;When you type &lt;code&gt;ls&lt;&#x2F;code&gt;, the shell does not magically know where &lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;ls&lt;&#x2F;code&gt; lives. It searches through a list of directories in order. That list is stored in an environment variable called &lt;code&gt;PATH&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You can see yours:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ echo $PATH
&#x2F;usr&#x2F;local&#x2F;bin:&#x2F;usr&#x2F;bin:&#x2F;bin:&#x2F;usr&#x2F;sbin:&#x2F;sbin
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The directories are separated by colons. The shell checks each one, left to right, for a file matching the command name. The first match wins.&lt;&#x2F;p&gt;
&lt;p&gt;If you type a command and get &lt;code&gt;command not found&lt;&#x2F;code&gt;, it means the shell searched every directory in PATH and found nothing. The program either does not exist, is not installed, or is in a directory that is not listed in PATH.&lt;&#x2F;p&gt;
&lt;p&gt;You can bypass PATH entirely by specifying the full path to a program:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ &#x2F;usr&#x2F;bin&#x2F;ls
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or a relative path:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ .&#x2F;my-program
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;.&#x2F;&lt;&#x2F;code&gt; prefix tells the shell to look in the current directory specifically, not to search PATH.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 18.2 -- PATH search order&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Command --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;30&quot; fill=&quot;#FFD700&quot; font-size=&quot;14&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;$ grep&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Search arrows --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;40&quot; x2=&quot;290&quot; y2=&quot;60&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowP18)&quot;&#x2F;&gt;
  &lt;!-- Directory 1 --&gt;
  &lt;rect x=&quot;120&quot; y=&quot;65&quot; width=&quot;340&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;87&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot;&gt;&#x2F;usr&#x2F;local&#x2F;bin&#x2F;&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;87&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;not found&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;100&quot; x2=&quot;290&quot; y2=&quot;110&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arrowP18)&quot;&#x2F;&gt;
  &lt;!-- Directory 2 --&gt;
  &lt;rect x=&quot;120&quot; y=&quot;115&quot; width=&quot;340&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;137&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot;&gt;&#x2F;usr&#x2F;bin&#x2F;&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;137&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;FOUND: &#x2F;usr&#x2F;bin&#x2F;grep&lt;&#x2F;text&gt;
  &lt;!-- Highlight --&gt;
  &lt;rect x=&quot;120&quot; y=&quot;115&quot; width=&quot;340&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- Stop indicator --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;150&quot; x2=&quot;290&quot; y2=&quot;165&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowG18b)&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;185&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Search stops&lt;&#x2F;text&gt;
  &lt;!-- Remaining directories (dimmed) --&gt;
  &lt;rect x=&quot;120&quot; y=&quot;200&quot; width=&quot;340&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#494D52&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;220&quot; fill=&quot;#494D52&quot; font-size=&quot;11&quot;&gt;&#x2F;bin&#x2F;&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;220&quot; fill=&quot;#494D52&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;not checked&lt;&#x2F;text&gt;
  &lt;rect x=&quot;120&quot; y=&quot;238&quot; width=&quot;340&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#494D52&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;258&quot; fill=&quot;#494D52&quot; font-size=&quot;11&quot;&gt;&#x2F;usr&#x2F;sbin&#x2F;&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;258&quot; fill=&quot;#494D52&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;not checked&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrowP18&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arrowG18b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;When you type &quot;grep&quot;, the shell walks through PATH directories left to right. It finds &#x2F;usr&#x2F;bin&#x2F;grep and stops searching. Later directories are never checked.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-major-shells&quot;&gt;The Major Shells&lt;&#x2F;h2&gt;
&lt;p&gt;The concept of a command-line shell is older than Linux. Here are the shells you are most likely to encounter:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sh-the-bourne-shell&quot;&gt;sh -- The Bourne Shell&lt;&#x2F;h3&gt;
&lt;p&gt;Written by Stephen Bourne at Bell Labs in 1979. It established the basic syntax that all later shells build on: command arguments, pipes, redirection, variables, control structures. On modern Linux systems, &lt;code&gt;&#x2F;bin&#x2F;sh&lt;&#x2F;code&gt; is usually a symlink to a lighter shell like &lt;code&gt;dash&lt;&#x2F;code&gt;, not the original Bourne shell.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bash-bourne-again-shell&quot;&gt;bash -- Bourne Again Shell&lt;&#x2F;h3&gt;
&lt;p&gt;The default shell on most Linux distributions. Written by Brian Fox for the GNU Project in 1989. It is backward-compatible with &lt;code&gt;sh&lt;&#x2F;code&gt; and adds interactive features like command history, tab completion, and programmable completion. When people say &quot;shell scripting&quot; without qualification, they usually mean bash.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zsh-z-shell&quot;&gt;zsh -- Z Shell&lt;&#x2F;h3&gt;
&lt;p&gt;The default shell on macOS since 2019. It offers everything bash does plus more advanced features: better tab completion, spelling correction, extended globbing patterns, and a large plugin ecosystem. Its syntax is mostly compatible with bash.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dash-debian-almquist-shell&quot;&gt;dash -- Debian Almquist Shell&lt;&#x2F;h3&gt;
&lt;p&gt;A minimal, fast shell used by Debian and Ubuntu for system scripts. It implements only the POSIX &lt;code&gt;sh&lt;&#x2F;code&gt; standard -- no bash extensions. When a system script says &lt;code&gt;#!&#x2F;bin&#x2F;sh&lt;&#x2F;code&gt;, it often runs under dash because dash starts faster than bash.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
All of these shells do the same fundamental job: read commands, find programs, run them. They differ in interactive features and scripting extensions, but the core loop is identical. If you learn bash, you can get by in any of them.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-shell-is-just-a-program&quot;&gt;The Shell Is Just a Program&lt;&#x2F;h2&gt;
&lt;p&gt;This is the key insight that trips up many beginners: the shell is not special hardware. It is not an operating system component. It is an ordinary user-space program, no different in principle from &lt;code&gt;ls&lt;&#x2F;code&gt; or &lt;code&gt;firefox&lt;&#x2F;code&gt; or &lt;code&gt;python3&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The kernel does not know or care that bash is a &quot;shell.&quot; From the kernel&#x27;s perspective, bash is just another process that occasionally calls &lt;code&gt;fork()&lt;&#x2F;code&gt;, &lt;code&gt;exec()&lt;&#x2F;code&gt;, and &lt;code&gt;wait()&lt;&#x2F;code&gt;. You could write your own shell in any language. Some people do -- it is a classic programming exercise.&lt;&#x2F;p&gt;
&lt;p&gt;What makes the shell feel special is that it is the first thing you interact with when you log in, and it is the thing that starts every other program you use from the command line. But that is a matter of convention, not privilege.&lt;&#x2F;p&gt;
&lt;p&gt;You can verify this by running a shell inside a shell:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ bash
$ echo &amp;quot;I am in a nested shell&amp;quot;
I am in a nested shell
$ exit
$ echo &amp;quot;Back to the original&amp;quot;
Back to the original
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The inner bash is a child process of the outer bash. When you type &lt;code&gt;exit&lt;&#x2F;code&gt;, the inner shell terminates and you return to the outer one. There is no limit to how deep you can nest, though there is rarely a reason to go more than one level.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 18.3 -- Nested shells are just nested processes&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 200&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;200&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Outer shell --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;20&quot; width=&quot;520&quot; height=&quot;160&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;50&quot; y=&quot;45&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot;&gt;bash (PID 1000)&lt;&#x2F;text&gt;
  &lt;!-- Inner shell --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;60&quot; width=&quot;460&quot; height=&quot;100&quot; rx=&quot;6&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;85&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot;&gt;bash (PID 1001) -- child of 1000&lt;&#x2F;text&gt;
  &lt;!-- Program inside inner shell --&gt;
  &lt;rect x=&quot;90&quot; y=&quot;100&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;110&quot; y=&quot;125&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;ls (PID 1002)&lt;&#x2F;text&gt;
  &lt;!-- Labels --&gt;
&lt;p&gt;&lt;text x=&quot;370&quot; y=&quot;125&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;$ exit kills PID 1001&lt;&#x2F;text&gt;
&lt;text x=&quot;370&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;returns to PID 1000&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Running &quot;bash&quot; inside bash creates a child shell process. Programs you run in the inner shell are grandchildren of the outer shell. Exiting the inner shell returns you to the outer one.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-login-shell-and-interactive-shells&quot;&gt;The Login Shell and Interactive Shells&lt;&#x2F;h2&gt;
&lt;p&gt;When you log in to a Linux system, the login process checks &lt;code&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;code&gt; to find which shell to start for your user account. That shell is your &lt;strong&gt;login shell&lt;&#x2F;strong&gt;. It is the root of your session -- every other program you launch descends from it.&lt;&#x2F;p&gt;
&lt;p&gt;A login shell reads extra configuration files when it starts. For bash, that means &lt;code&gt;~&#x2F;.bash_profile&lt;&#x2F;code&gt; or &lt;code&gt;~&#x2F;.profile&lt;&#x2F;code&gt;. These files set up your environment: your PATH, your preferred editor, your prompt format.&lt;&#x2F;p&gt;
&lt;p&gt;When you open a new terminal window in a graphical desktop, you usually get a non-login &lt;strong&gt;interactive shell&lt;&#x2F;strong&gt;. It reads &lt;code&gt;~&#x2F;.bashrc&lt;&#x2F;code&gt; instead. The distinction matters because some settings only need to happen once per login (like adding directories to PATH), while others should apply to every new shell (like aliases and prompt configuration).&lt;&#x2F;p&gt;
&lt;p&gt;We will explore these configuration files in detail in Article 21.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Login shell&lt;&#x2F;strong&gt;
The shell started when you first log in to the system. It reads additional startup files (like ~&#x2F;.profile) that set up your session environment. You can check if your current shell is a login shell by running &quot;echo $0&quot; -- a login shell&#x27;s name starts with a hyphen, like &quot;-bash&quot;.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-you-have-learned&quot;&gt;What You Have Learned&lt;&#x2F;h2&gt;
&lt;p&gt;The shell is a program. It lives on disk at a path like &lt;code&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt;. It runs in a loop: read a command, parse it, find the program, fork a child process, execute the program in that child, wait for it to finish, repeat. Some commands are built into the shell itself because they need to modify the shell&#x27;s own state. The shell finds external programs by searching directories listed in the PATH variable. There are several shells to choose from -- bash, zsh, dash, and others -- but they all implement the same fundamental loop.&lt;&#x2F;p&gt;
&lt;p&gt;The terminal is the window. The shell is the brain inside it.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;19-standard-io&#x2F;&quot;&gt;Standard I&#x2F;O&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Users, Groups, and Permissions</title>
        <published>2025-01-21T00:00:00+00:00</published>
        <updated>2025-01-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/17-users-groups-and-permissions/"/>
        <id>https://t34ch.tech/coldboot/articles/17-users-groups-and-permissions/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/17-users-groups-and-permissions/">&lt;p&gt;A computer with one user and no network connection does not need access control. But the moment a second person can log in, or the machine connects to the internet, you need a way to separate what different people and programs are allowed to do. Who can read your files? Who can install software? Who can shut down the machine?&lt;&#x2F;p&gt;
&lt;p&gt;Linux answers these questions with a system that dates back to the original Unix: users, groups, and permission bits. Every file, every process, and every action on the system is governed by this model.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;users-are-numbers&quot;&gt;Users Are Numbers&lt;&#x2F;h2&gt;
&lt;p&gt;When you log into a Linux system, you type a username like &quot;alice&quot; or &quot;admin.&quot; But internally, the kernel does not care about names. It tracks users by number. Every user has a &lt;strong&gt;UID&lt;&#x2F;strong&gt; -- a user identifier, which is an integer.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;UID&lt;&#x2F;th&gt;&lt;th&gt;Conventional Meaning&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;root (superuser)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1-999&lt;&#x2F;td&gt;&lt;td&gt;System accounts (services)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1000+&lt;&#x2F;td&gt;&lt;td&gt;Regular human users&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The mapping between names and numbers is stored in &lt;code&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;code&gt;. Despite the name, this file does not contain passwords (not anymore -- it did in the 1970s). Each line describes one user:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;alice:x:1000:1000:Alice Smith:&#x2F;home&#x2F;alice:&#x2F;bin&#x2F;bash
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The fields, separated by colons, are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Username (&lt;code&gt;alice&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Password placeholder (&lt;code&gt;x&lt;&#x2F;code&gt; -- actual password is in &lt;code&gt;&#x2F;etc&#x2F;shadow&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;UID (&lt;code&gt;1000&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Primary GID (&lt;code&gt;1000&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Comment &#x2F; full name (&lt;code&gt;Alice Smith&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Home directory (&lt;code&gt;&#x2F;home&#x2F;alice&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Login shell (&lt;code&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: UID (User Identifier)&lt;&#x2F;strong&gt;
A non-negative integer that uniquely identifies a user on the system. The kernel uses UIDs, not usernames, for all access control decisions. UID 0 is always the root superuser.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 17a -- The &#x2F;etc&#x2F;passwd file structure&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 260&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;260&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Header --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Entry line --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;40&quot; width=&quot;540&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;59&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;alice:x:1000:1000:Alice Smith:&#x2F;home&#x2F;alice:&#x2F;bin&#x2F;bash&lt;&#x2F;text&gt;
  &lt;!-- Field breakdown --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;90&quot; width=&quot;75&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;57&quot; y=&quot;108&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;username&lt;&#x2F;text&gt;
  &lt;text x=&quot;57&quot; y=&quot;122&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;alice&lt;&#x2F;text&gt;
  &lt;rect x=&quot;100&quot; y=&quot;90&quot; width=&quot;35&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;117&quot; y=&quot;108&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;pw&lt;&#x2F;text&gt;
  &lt;text x=&quot;117&quot; y=&quot;122&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;x&lt;&#x2F;text&gt;
  &lt;rect x=&quot;140&quot; y=&quot;90&quot; width=&quot;55&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;167&quot; y=&quot;108&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;UID&lt;&#x2F;text&gt;
  &lt;text x=&quot;167&quot; y=&quot;122&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;1000&lt;&#x2F;text&gt;
  &lt;rect x=&quot;200&quot; y=&quot;90&quot; width=&quot;55&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;227&quot; y=&quot;108&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;GID&lt;&#x2F;text&gt;
  &lt;text x=&quot;227&quot; y=&quot;122&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;1000&lt;&#x2F;text&gt;
  &lt;rect x=&quot;260&quot; y=&quot;90&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;310&quot; y=&quot;108&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;comment&lt;&#x2F;text&gt;
  &lt;text x=&quot;310&quot; y=&quot;122&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Alice Smith&lt;&#x2F;text&gt;
  &lt;rect x=&quot;365&quot; y=&quot;90&quot; width=&quot;105&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;417&quot; y=&quot;108&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;home dir&lt;&#x2F;text&gt;
  &lt;text x=&quot;417&quot; y=&quot;122&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;home&#x2F;alice&lt;&#x2F;text&gt;
  &lt;rect x=&quot;475&quot; y=&quot;90&quot; width=&quot;85&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;517&quot; y=&quot;108&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;shell&lt;&#x2F;text&gt;
  &lt;text x=&quot;517&quot; y=&quot;122&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;bin&#x2F;bash&lt;&#x2F;text&gt;
  &lt;!-- Pointer lines from entry to fields --&gt;
  &lt;line x1=&quot;45&quot; y1=&quot;68&quot; x2=&quot;57&quot; y2=&quot;87&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;line x1=&quot;110&quot; y1=&quot;68&quot; x2=&quot;117&quot; y2=&quot;87&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;line x1=&quot;155&quot; y1=&quot;68&quot; x2=&quot;167&quot; y2=&quot;87&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;line x1=&quot;195&quot; y1=&quot;68&quot; x2=&quot;227&quot; y2=&quot;87&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;line x1=&quot;280&quot; y1=&quot;68&quot; x2=&quot;310&quot; y2=&quot;87&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;line x1=&quot;400&quot; y1=&quot;68&quot; x2=&quot;417&quot; y2=&quot;87&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;line x1=&quot;505&quot; y1=&quot;68&quot; x2=&quot;517&quot; y2=&quot;87&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;!-- Other entries --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;150&quot; width=&quot;540&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;169&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;root:x:0:0:root:&#x2F;root:&#x2F;bin&#x2F;bash&lt;&#x2F;text&gt;
  &lt;rect x=&quot;20&quot; y=&quot;183&quot; width=&quot;540&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;202&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;nobody:x:65534:65534:Nobody:&#x2F;nonexistent:&#x2F;usr&#x2F;sbin&#x2F;nologin&lt;&#x2F;text&gt;
  &lt;rect x=&quot;20&quot; y=&quot;216&quot; width=&quot;540&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;235&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;sshd:x:110:65534::&#x2F;run&#x2F;sshd:&#x2F;usr&#x2F;sbin&#x2F;nologin&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Each line in &#x2F;etc&#x2F;passwd maps a username to a UID, home directory, and login shell. System accounts use &#x2F;usr&#x2F;sbin&#x2F;nologin to prevent interactive login.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;passwords-and-etc-shadow&quot;&gt;Passwords and &#x2F;etc&#x2F;shadow&lt;&#x2F;h2&gt;
&lt;p&gt;The actual password hashes live in &lt;code&gt;&#x2F;etc&#x2F;shadow&lt;&#x2F;code&gt;, which is readable only by root. This separation exists because &lt;code&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;code&gt; must be world-readable (programs need to look up usernames), but password hashes should not be.&lt;&#x2F;p&gt;
&lt;p&gt;A line in &lt;code&gt;&#x2F;etc&#x2F;shadow&lt;&#x2F;code&gt; looks like:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;alice:$6$rounds=5000$salt$hash...:19500:0:99999:7:::
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;$6$&lt;&#x2F;code&gt; prefix indicates SHA-512 hashing. The salt is a random string that ensures two users with the same password produce different hashes. The remaining fields control password aging -- when it was last changed, when it expires, and how much warning to give.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Password hash&lt;&#x2F;strong&gt;
A one-way mathematical transformation of a password. The system stores the hash, not the password itself. When you log in, the system hashes what you typed and compares it to the stored hash. This means that even someone who reads &#x2F;etc&#x2F;shadow cannot directly recover the passwords.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;groups&quot;&gt;Groups&lt;&#x2F;h2&gt;
&lt;p&gt;A &lt;strong&gt;group&lt;&#x2F;strong&gt; is a named collection of users, identified by a &lt;strong&gt;GID&lt;&#x2F;strong&gt; (group identifier). Groups exist so you can grant permissions to multiple users at once without listing them individually.&lt;&#x2F;p&gt;
&lt;p&gt;Every user has a &lt;strong&gt;primary group&lt;&#x2F;strong&gt; (set in &lt;code&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;code&gt;) and can belong to additional &lt;strong&gt;supplementary groups&lt;&#x2F;strong&gt; (set in &lt;code&gt;&#x2F;etc&#x2F;group&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;&#x2F;etc&#x2F;group&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;developers:x:1001:alice,bob,carol
www-data:x:33:alice
sudo:x:27:alice
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each line has four fields: group name, password placeholder, GID, and a comma-separated list of members.&lt;&#x2F;p&gt;
&lt;p&gt;Check your own groups with:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;id
groups
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;id&lt;&#x2F;code&gt; command shows your UID, primary GID, and all supplementary groups. This is exactly what the kernel sees when it checks your permissions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-root-user&quot;&gt;The Root User&lt;&#x2F;h2&gt;
&lt;p&gt;UID 0 is &lt;strong&gt;root&lt;&#x2F;strong&gt;, the superuser. Root bypasses almost all permission checks. Root can read any file, write any file, kill any process, mount filesystems, load kernel modules, and change the system clock. There is no higher authority on a Linux system.&lt;&#x2F;p&gt;
&lt;p&gt;This is both powerful and dangerous. A mistake as root can destroy the system. A compromised root account means an attacker controls everything. This is why modern practice avoids logging in as root directly. Instead, you log in as a normal user and use &lt;code&gt;sudo&lt;&#x2F;code&gt; to run individual commands with root privileges.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update          # Run this one command as root
sudo -i                  # Open a root shell (use with caution)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;sudo&lt;&#x2F;code&gt; checks &lt;code&gt;&#x2F;etc&#x2F;sudoers&lt;&#x2F;code&gt; to determine whether the requesting user is allowed to elevate. On most desktop distributions, the first user created during installation is granted sudo access.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Root (UID 0) can do anything on the system. Normal users are limited by permission checks. Use sudo for temporary privilege escalation instead of logging in as root. This limits the damage from mistakes and compromises.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;file-permissions&quot;&gt;File Permissions&lt;&#x2F;h2&gt;
&lt;p&gt;Every file and directory on the system has three sets of permission bits: one for the &lt;strong&gt;owner&lt;&#x2F;strong&gt;, one for the &lt;strong&gt;group&lt;&#x2F;strong&gt;, and one for &lt;strong&gt;others&lt;&#x2F;strong&gt; (everyone else).&lt;&#x2F;p&gt;
&lt;p&gt;Each set has three bits:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Bit&lt;&#x2F;th&gt;&lt;th&gt;Letter&lt;&#x2F;th&gt;&lt;th&gt;On a file&lt;&#x2F;th&gt;&lt;th&gt;On a directory&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Read&lt;&#x2F;td&gt;&lt;td&gt;r&lt;&#x2F;td&gt;&lt;td&gt;Can read the file contents&lt;&#x2F;td&gt;&lt;td&gt;Can list the directory contents&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Write&lt;&#x2F;td&gt;&lt;td&gt;w&lt;&#x2F;td&gt;&lt;td&gt;Can modify the file&lt;&#x2F;td&gt;&lt;td&gt;Can create&#x2F;delete files in the directory&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Execute&lt;&#x2F;td&gt;&lt;td&gt;x&lt;&#x2F;td&gt;&lt;td&gt;Can run the file as a program&lt;&#x2F;td&gt;&lt;td&gt;Can enter (cd into) the directory&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The &lt;code&gt;ls -l&lt;&#x2F;code&gt; command shows permissions:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;-rwxr-xr-- 1 alice developers 4096 Jan 18 10:30 script.sh
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Reading the permission string &lt;code&gt;-rwxr-xr--&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;First character: file type (&lt;code&gt;-&lt;&#x2F;code&gt; = regular file, &lt;code&gt;d&lt;&#x2F;code&gt; = directory, &lt;code&gt;l&lt;&#x2F;code&gt; = symlink)&lt;&#x2F;li&gt;
&lt;li&gt;Characters 2-4: owner permissions (&lt;code&gt;rwx&lt;&#x2F;code&gt; = read, write, execute)&lt;&#x2F;li&gt;
&lt;li&gt;Characters 5-7: group permissions (&lt;code&gt;r-x&lt;&#x2F;code&gt; = read, execute, no write)&lt;&#x2F;li&gt;
&lt;li&gt;Characters 8-10: others permissions (&lt;code&gt;r--&lt;&#x2F;code&gt; = read only)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 17b -- File permission bits&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- File line --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;30&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;-rwxr-xr-- 1 alice developers script.sh&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Type --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;50&quot; width=&quot;50&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;45&quot; y=&quot;68&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;type&lt;&#x2F;text&gt;
  &lt;text x=&quot;45&quot; y=&quot;92&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;24&quot; text-anchor=&quot;middle&quot;&gt;-&lt;&#x2F;text&gt;
  &lt;line x1=&quot;135&quot; y1=&quot;24&quot; x2=&quot;45&quot; y2=&quot;47&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;!-- Owner --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;50&quot; width=&quot;120&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;68&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;owner (alice)&lt;&#x2F;text&gt;
  &lt;text x=&quot;105&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;22&quot;&gt;r&lt;&#x2F;text&gt;
  &lt;text x=&quot;127&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;22&quot;&gt;w&lt;&#x2F;text&gt;
  &lt;text x=&quot;152&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;22&quot;&gt;x&lt;&#x2F;text&gt;
  &lt;line x1=&quot;175&quot; y1=&quot;24&quot; x2=&quot;140&quot; y2=&quot;47&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;!-- Group --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;50&quot; width=&quot;140&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;280&quot; y=&quot;68&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;group (developers)&lt;&#x2F;text&gt;
  &lt;text x=&quot;240&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;22&quot;&gt;r&lt;&#x2F;text&gt;
  &lt;text x=&quot;268&quot; y=&quot;94&quot; fill=&quot;#C0392B&quot; font-size=&quot;22&quot;&gt;-&lt;&#x2F;text&gt;
  &lt;text x=&quot;293&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;22&quot;&gt;x&lt;&#x2F;text&gt;
  &lt;line x1=&quot;225&quot; y1=&quot;24&quot; x2=&quot;280&quot; y2=&quot;47&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;!-- Others --&gt;
  &lt;rect x=&quot;360&quot; y=&quot;50&quot; width=&quot;120&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;68&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;others&lt;&#x2F;text&gt;
  &lt;text x=&quot;387&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;22&quot;&gt;r&lt;&#x2F;text&gt;
  &lt;text x=&quot;415&quot; y=&quot;94&quot; fill=&quot;#C0392B&quot; font-size=&quot;22&quot;&gt;-&lt;&#x2F;text&gt;
  &lt;text x=&quot;440&quot; y=&quot;94&quot; fill=&quot;#C0392B&quot; font-size=&quot;22&quot;&gt;-&lt;&#x2F;text&gt;
  &lt;line x1=&quot;275&quot; y1=&quot;24&quot; x2=&quot;420&quot; y2=&quot;47&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;!-- Octal representation --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;140&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Octal Representation&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;80&quot; y=&quot;155&quot; width=&quot;120&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;173&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;r=4 w=2 x=1&lt;&#x2F;text&gt;
  &lt;text x=&quot;140&quot; y=&quot;195&quot; fill=&quot;#FFD700&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;7&lt;&#x2F;text&gt;
  &lt;rect x=&quot;210&quot; y=&quot;155&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;280&quot; y=&quot;173&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;r=4 w=0 x=1&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;195&quot; fill=&quot;#00BFFF&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;5&lt;&#x2F;text&gt;
  &lt;rect x=&quot;360&quot; y=&quot;155&quot; width=&quot;120&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;173&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;r=4 w=0 x=0&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;195&quot; fill=&quot;#FF6600&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;4&lt;&#x2F;text&gt;
  &lt;!-- Result --&gt;
  &lt;rect x=&quot;190&quot; y=&quot;225&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;245&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;chmod 754 script.sh&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;258&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;sets -rwxr-xr--&lt;&#x2F;text&gt;
  &lt;!-- Common patterns --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;290&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Common: 644 (files), 755 (executables&#x2F;dirs), 600 (private), 777 (everything -- avoid)&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Permission bits are grouped into owner, group, and others. Each group has read, write, and execute. The octal number is the sum of the bit values (r=4, w=2, x=1).&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h3 id=&quot;octal-notation&quot;&gt;Octal Notation&lt;&#x2F;h3&gt;
&lt;p&gt;Each permission bit has a numeric value: read = 4, write = 2, execute = 1. You add them up for each group. The permissions &lt;code&gt;rwxr-xr--&lt;&#x2F;code&gt; become &lt;code&gt;754&lt;&#x2F;code&gt;: owner gets 4+2+1=7, group gets 4+0+1=5, others get 4+0+0=4.&lt;&#x2F;p&gt;
&lt;p&gt;You can set permissions with &lt;code&gt;chmod&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;chmod 755 script.sh    # rwxr-xr-x
chmod 644 document.txt # rw-r--r--
chmod 600 secret.key   # rw-------
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also use symbolic notation:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;chmod u+x script.sh     # Add execute for owner
chmod g-w file.txt       # Remove write for group
chmod o= file.txt        # Remove all permissions for others
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;changing-ownership&quot;&gt;Changing Ownership&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;chown&lt;&#x2F;code&gt; command changes the owner and group:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;chown alice:developers file.txt    # Set owner and group
chown alice file.txt               # Set owner only
chown :developers file.txt         # Set group only
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Only root can change the owner of a file. A regular user can only change the group to a group they belong to.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-the-kernel-checks-permissions&quot;&gt;How the Kernel Checks Permissions&lt;&#x2F;h2&gt;
&lt;p&gt;When a process tries to access a file, the kernel follows a simple algorithm:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;If the process runs as UID 0 (root), allow everything. Check done.&lt;&#x2F;li&gt;
&lt;li&gt;If the process&#x27;s UID matches the file&#x27;s owner UID, use the owner permission bits.&lt;&#x2F;li&gt;
&lt;li&gt;If the process&#x27;s GID (or any supplementary GID) matches the file&#x27;s group GID, use the group permission bits.&lt;&#x2F;li&gt;
&lt;li&gt;Otherwise, use the others permission bits.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is a strictly ordered check. If you are the owner, the owner bits apply even if the group bits are more permissive. This occasionally surprises people: a file owned by alice with permissions &lt;code&gt;---rwxrwx&lt;&#x2F;code&gt; is unreadable by alice, even though both the group and others have full access.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 17c -- Permission check algorithm&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Start --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;10&quot; width=&quot;180&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;33&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Process opens file&lt;&#x2F;text&gt;
  &lt;!-- UID 0? --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;65&quot; width=&quot;180&quot; height=&quot;35&quot; rx=&quot;15&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;88&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;UID == 0 (root)?&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;45&quot; x2=&quot;290&quot; y2=&quot;65&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- Yes -&gt; allow --&gt;
  &lt;rect x=&quot;440&quot; y=&quot;65&quot; width=&quot;100&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;490&quot; y=&quot;88&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;ALLOW&lt;&#x2F;text&gt;
  &lt;line x1=&quot;380&quot; y1=&quot;82&quot; x2=&quot;435&quot; y2=&quot;82&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;408&quot; y=&quot;76&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot;&gt;yes&lt;&#x2F;text&gt;
  &lt;!-- No -&gt; owner check --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;125&quot; width=&quot;180&quot; height=&quot;35&quot; rx=&quot;15&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;148&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;UID == owner?&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;100&quot; x2=&quot;290&quot; y2=&quot;125&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;280&quot; y=&quot;118&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;no&lt;&#x2F;text&gt;
  &lt;!-- Yes -&gt; check owner bits --&gt;
  &lt;rect x=&quot;440&quot; y=&quot;125&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;500&quot; y=&quot;148&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Owner bits&lt;&#x2F;text&gt;
  &lt;line x1=&quot;380&quot; y1=&quot;142&quot; x2=&quot;435&quot; y2=&quot;142&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;408&quot; y=&quot;136&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot;&gt;yes&lt;&#x2F;text&gt;
  &lt;!-- No -&gt; group check --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;185&quot; width=&quot;180&quot; height=&quot;35&quot; rx=&quot;15&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;208&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;GID in file group?&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;160&quot; x2=&quot;290&quot; y2=&quot;185&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;280&quot; y=&quot;178&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;no&lt;&#x2F;text&gt;
  &lt;!-- Yes -&gt; check group bits --&gt;
  &lt;rect x=&quot;440&quot; y=&quot;185&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;500&quot; y=&quot;208&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Group bits&lt;&#x2F;text&gt;
  &lt;line x1=&quot;380&quot; y1=&quot;202&quot; x2=&quot;435&quot; y2=&quot;202&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;408&quot; y=&quot;196&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot;&gt;yes&lt;&#x2F;text&gt;
  &lt;!-- No -&gt; others bits --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;245&quot; width=&quot;180&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;268&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Use Others bits&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;220&quot; x2=&quot;290&quot; y2=&quot;245&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;280&quot; y=&quot;238&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;no&lt;&#x2F;text&gt;
  &lt;!-- Denied --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;300&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;320&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;If bit not set: EACCES (denied)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;280&quot; x2=&quot;290&quot; y2=&quot;300&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Connect owner&#x2F;group bits to denied --&gt;
  &lt;line x1=&quot;500&quot; y1=&quot;160&quot; x2=&quot;500&quot; y2=&quot;293&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;500&quot; y1=&quot;220&quot; x2=&quot;500&quot; y2=&quot;293&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;500&quot; y1=&quot;293&quot; x2=&quot;385&quot; y2=&quot;310&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,3&quot;&#x2F;&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The kernel checks UID 0 first (always allowed), then owner match, then group match, then falls through to others. Only one set of bits is ever applied.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;special-permission-bits&quot;&gt;Special Permission Bits&lt;&#x2F;h2&gt;
&lt;p&gt;Beyond the basic rwx bits, there are three special bits that modify how files and directories behave.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setuid-set-user-id&quot;&gt;setuid (Set User ID)&lt;&#x2F;h3&gt;
&lt;p&gt;When a program with the setuid bit set is executed, it runs with the UID of the file&#x27;s owner rather than the UID of the user who launched it. This is how normal users can change their own passwords -- the &lt;code&gt;passwd&lt;&#x2F;code&gt; command is owned by root with setuid set:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;ls -l &#x2F;usr&#x2F;bin&#x2F;passwd
-rwsr-xr-x 1 root root 68208 Jan 18 10:30 &#x2F;usr&#x2F;bin&#x2F;passwd
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice the &lt;code&gt;s&lt;&#x2F;code&gt; where the owner&#x27;s execute bit would be. When alice runs &lt;code&gt;passwd&lt;&#x2F;code&gt;, the process runs with UID 0 (root), giving it permission to write to &lt;code&gt;&#x2F;etc&#x2F;shadow&lt;&#x2F;code&gt;. When &lt;code&gt;passwd&lt;&#x2F;code&gt; finishes, the elevated privileges disappear.&lt;&#x2F;p&gt;
&lt;p&gt;setuid is powerful and dangerous. A bug in a setuid-root program can give any user root access. This is why the set of setuid programs on a system is kept deliberately small, and security auditors pay special attention to them.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setgid-set-group-id&quot;&gt;setgid (Set Group ID)&lt;&#x2F;h3&gt;
&lt;p&gt;Similar to setuid, but for the group. On a file, it makes the program run with the file&#x27;s group. On a directory, it has a different effect: new files created inside the directory inherit the directory&#x27;s group instead of the creating user&#x27;s primary group. This is useful for shared project directories.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-sticky-bit&quot;&gt;The Sticky Bit&lt;&#x2F;h3&gt;
&lt;p&gt;On a directory, the sticky bit prevents users from deleting files they do not own, even if they have write permission on the directory. The classic example is &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;ls -ld &#x2F;tmp
drwxrwxrwt 15 root root 4096 Jan 18 10:30 &#x2F;tmp
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;t&lt;&#x2F;code&gt; at the end is the sticky bit. Everyone can create files in &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt;, but you can only delete your own files. Without the sticky bit, anyone with write access to the directory could delete anyone else&#x27;s files.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: setuid&lt;&#x2F;strong&gt;
A special permission bit on executable files. When set, the program runs with the privileges of the file&#x27;s owner, not the user who executed it. This is how programs like passwd and sudo gain temporary root access.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;process-credentials&quot;&gt;Process Credentials&lt;&#x2F;h2&gt;
&lt;p&gt;Every process inherits the UID and GID of the user who started it. When Alice&#x27;s shell (running as UID 1000) runs &lt;code&gt;ls&lt;&#x2F;code&gt;, the &lt;code&gt;ls&lt;&#x2F;code&gt; process also runs as UID 1000. When &lt;code&gt;ls&lt;&#x2F;code&gt; tries to read a directory, the kernel checks UID 1000&#x27;s permissions.&lt;&#x2F;p&gt;
&lt;p&gt;A process actually carries several IDs:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Real UID&lt;&#x2F;strong&gt; -- the user who started the process&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Effective UID&lt;&#x2F;strong&gt; -- the UID used for permission checks (usually the same as real, unless setuid is involved)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Saved UID&lt;&#x2F;strong&gt; -- allows a process to temporarily drop and regain elevated privileges&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;When a setuid program runs, the effective UID changes to the file owner, but the real UID stays as the invoking user. This is how the program knows who actually ran it.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Permissions are checked against the process&#x27;s effective UID and GID, not the username. Every file access, every signal delivery, every system call that requires authorization goes through this check. The entire security model rests on these numeric identifiers.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;why-this-matters-for-security&quot;&gt;Why This Matters for Security&lt;&#x2F;h2&gt;
&lt;p&gt;The user&#x2F;group&#x2F;permission model is the first line of defense on a Linux system. It works because:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Isolation.&lt;&#x2F;strong&gt; Each user&#x27;s files are protected from other users by default. A compromised web server running as &lt;code&gt;www-data&lt;&#x2F;code&gt; (UID 33) cannot read files in &lt;code&gt;&#x2F;home&#x2F;alice&#x2F;&lt;&#x2F;code&gt; (owned by UID 1000, mode 700).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Least privilege.&lt;&#x2F;strong&gt; Services run as dedicated, unprivileged users. The SSH daemon runs as &lt;code&gt;sshd&lt;&#x2F;code&gt;. The web server runs as &lt;code&gt;www-data&lt;&#x2F;code&gt;. If one service is compromised, the attacker gets only that service&#x27;s permissions, not root.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Audit trail.&lt;&#x2F;strong&gt; Every process carries a UID. Logs record which user performed each action. This makes it possible to trace what happened after a security incident.&lt;&#x2F;p&gt;
&lt;p&gt;The model is not perfect. It has no concept of fine-grained capabilities beyond the binary root&#x2F;non-root distinction. (Linux capabilities and mandatory access control systems like SELinux and AppArmor add more granularity, but those build on top of the basic model.) It does not protect against a careless root user. And it requires discipline -- a single &lt;code&gt;chmod 777&lt;&#x2F;code&gt; on a sensitive directory can undo all the protection.&lt;&#x2F;p&gt;
&lt;p&gt;But for a system designed in the 1970s, it has proven remarkably durable. Every modern Linux system, from phones to supercomputers, still uses these same UID and GID checks as the foundation of its security.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;essential-commands&quot;&gt;Essential Commands&lt;&#x2F;h2&gt;
&lt;pre&gt;&lt;code&gt;id                       # Show your UID, GID, and groups
whoami                   # Show your username
ls -la                   # Show file permissions
chmod 640 file           # Set permissions
chown user:group file    # Change ownership
passwd                   # Change your password
sudo command             # Run a command as root
su - username            # Switch to another user
getent passwd alice      # Look up a user
getent group developers  # Look up a group
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These commands map directly to the concepts in this article. &lt;code&gt;id&lt;&#x2F;code&gt; shows the kernel&#x27;s view of who you are. &lt;code&gt;ls -la&lt;&#x2F;code&gt; shows the kernel&#x27;s view of who owns a file. &lt;code&gt;chmod&lt;&#x2F;code&gt; and &lt;code&gt;chown&lt;&#x2F;code&gt; change those values. Everything else in the system -- every permission error, every &quot;access denied&quot; message, every security policy -- traces back to these fundamentals.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;18-what-a-shell-actually-is&#x2F;&quot;&gt;What a Shell Actually Is&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The TTY and Terminal</title>
        <published>2025-01-20T00:00:00+00:00</published>
        <updated>2025-01-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/16-the-tty-and-terminal/"/>
        <id>https://t34ch.tech/coldboot/articles/16-the-tty-and-terminal/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/16-the-tty-and-terminal/">&lt;p&gt;Open a terminal on your Linux system. You see a dark window with a blinking cursor, waiting for you to type. This seems simple -- you type, the computer responds. But between your keyboard and the program reading your input, there is a chain of abstraction layers with roots going back to the 1800s.&lt;&#x2F;p&gt;
&lt;p&gt;The word &quot;terminal&quot; and the abbreviation &quot;TTY&quot; both come from physical machines that no longer exist. Understanding where they came from explains why the system works the way it does today.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-teletypes-to-terminals&quot;&gt;From Teletypes to Terminals&lt;&#x2F;h2&gt;
&lt;p&gt;In the 1960s and 1970s, computers did not have monitors. Users interacted with the machine through a &lt;strong&gt;teletype&lt;&#x2F;strong&gt; (also called a teleprinter or TTY) -- a mechanical device with a keyboard and a printer. You typed a command on the keyboard. The computer&#x27;s response was printed on paper.&lt;&#x2F;p&gt;
&lt;p&gt;The teletype communicated with the computer over a serial line. Each keystroke was converted to an electrical signal (using a code called ASCII), sent down the wire, and received by the computer. The computer&#x27;s response traveled back the same way, driving the print mechanism.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: TTY&lt;&#x2F;strong&gt;
Short for &quot;teletype&quot; or &quot;teletypewriter.&quot; Originally a physical printing terminal connected to a computer via a serial line. In modern Linux, TTY refers to any terminal device -- physical or virtual -- that provides a text interface between a user and the system.
&lt;&#x2F;div&gt;
&lt;p&gt;By the late 1970s, teletypes were replaced by &lt;strong&gt;video terminals&lt;&#x2F;strong&gt; -- screens with keyboards. The DEC VT100 (1978) became the standard. Instead of printing on paper, it displayed text on a CRT screen. But it still connected to the computer over a serial line, and the computer still treated it as a TTY.&lt;&#x2F;p&gt;
&lt;p&gt;The physical terminals eventually disappeared too, replaced by terminal emulators -- software programs like GNOME Terminal, Alacritty, or xterm that simulate a VT100 (or its successors) in a window on your screen. But the kernel still uses the same abstraction it used for physical teletypes. That abstraction is the TTY subsystem.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 16a -- Evolution of terminals&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 240&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;240&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Era 1: Teletype --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;30&quot; width=&quot;150&quot; height=&quot;100&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;52&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;1960s-1970s&lt;&#x2F;text&gt;
  &lt;text x=&quot;95&quot; y=&quot;72&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Teletype&lt;&#x2F;text&gt;
  &lt;text x=&quot;95&quot; y=&quot;92&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Mechanical printer&lt;&#x2F;text&gt;
  &lt;text x=&quot;95&quot; y=&quot;106&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Serial line to host&lt;&#x2F;text&gt;
  &lt;text x=&quot;95&quot; y=&quot;120&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Paper output&lt;&#x2F;text&gt;
  &lt;!-- Era 2: Video terminal --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;30&quot; width=&quot;150&quot; height=&quot;100&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;285&quot; y=&quot;52&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;1978-1990s&lt;&#x2F;text&gt;
  &lt;text x=&quot;285&quot; y=&quot;72&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Video Terminal&lt;&#x2F;text&gt;
  &lt;text x=&quot;285&quot; y=&quot;92&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;CRT screen (VT100)&lt;&#x2F;text&gt;
  &lt;text x=&quot;285&quot; y=&quot;106&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Serial line to host&lt;&#x2F;text&gt;
  &lt;text x=&quot;285&quot; y=&quot;120&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Screen output&lt;&#x2F;text&gt;
  &lt;!-- Era 3: Terminal emulator --&gt;
  &lt;rect x=&quot;400&quot; y=&quot;30&quot; width=&quot;160&quot; height=&quot;100&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;52&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;1990s-today&lt;&#x2F;text&gt;
  &lt;text x=&quot;480&quot; y=&quot;72&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Terminal Emulator&lt;&#x2F;text&gt;
  &lt;text x=&quot;480&quot; y=&quot;92&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Software window&lt;&#x2F;text&gt;
  &lt;text x=&quot;480&quot; y=&quot;106&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;PTY to kernel&lt;&#x2F;text&gt;
  &lt;text x=&quot;480&quot; y=&quot;120&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Pixel output&lt;&#x2F;text&gt;
  &lt;!-- Arrows --&gt;
  &lt;line x1=&quot;170&quot; y1=&quot;80&quot; x2=&quot;205&quot; y2=&quot;80&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;202,74 212,80 202,86&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;80&quot; x2=&quot;395&quot; y2=&quot;80&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;392,74 402,80 392,86&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;!-- Common thread --&gt;
  &lt;rect x=&quot;120&quot; y=&quot;165&quot; width=&quot;340&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;185&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Kernel TTY Subsystem&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;200&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Same abstraction layer across all three eras&lt;&#x2F;text&gt;
  &lt;line x1=&quot;95&quot; y1=&quot;130&quot; x2=&quot;200&quot; y2=&quot;170&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;285&quot; y1=&quot;130&quot; x2=&quot;285&quot; y2=&quot;165&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;130&quot; x2=&quot;380&quot; y2=&quot;170&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,3&quot;&#x2F;&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The hardware changed three times, but the kernel abstraction remained. Modern terminal emulators still speak the same protocol that physical teletypes used.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;virtual-consoles&quot;&gt;Virtual Consoles&lt;&#x2F;h2&gt;
&lt;p&gt;Before looking at terminal emulators, there is a simpler kind of terminal built directly into the kernel: the &lt;strong&gt;virtual console&lt;&#x2F;strong&gt;. If you press Ctrl+Alt+F1 through Ctrl+Alt+F6 on a Linux system, you switch between virtual consoles. Each one is a full-screen text terminal, managed entirely by the kernel without any graphical environment.&lt;&#x2F;p&gt;
&lt;p&gt;These are the &lt;code&gt;&#x2F;dev&#x2F;tty1&lt;&#x2F;code&gt; through &lt;code&gt;&#x2F;dev&#x2F;tty6&lt;&#x2F;code&gt; devices. They are real TTY devices -- the kernel draws text directly to the video card&#x27;s framebuffer. When your graphical desktop fails to start, these consoles are your fallback.&lt;&#x2F;p&gt;
&lt;p&gt;Your graphical desktop typically runs on one of the higher-numbered virtual consoles (often tty2 or tty7, depending on the distribution). The terminal emulator you open within your desktop is something different -- it uses a &lt;strong&gt;pseudoterminal&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-pseudoterminal-pty&quot;&gt;The Pseudoterminal (PTY)&lt;&#x2F;h2&gt;
&lt;p&gt;A terminal emulator like GNOME Terminal or Alacritty is a regular graphical application. It draws a window, renders text using a font, and handles keyboard input. But the shell running inside it expects to talk to a TTY device. How does a regular program pretend to be a hardware terminal?&lt;&#x2F;p&gt;
&lt;p&gt;The answer is the &lt;strong&gt;pseudoterminal (PTY)&lt;&#x2F;strong&gt; -- a pair of virtual devices created by the kernel. One end is the &lt;strong&gt;master&lt;&#x2F;strong&gt; (also called the PTY master or ptmx). The other end is the &lt;strong&gt;slave&lt;&#x2F;strong&gt; (also called the PTY slave or pts).&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Pseudoterminal (PTY)&lt;&#x2F;strong&gt;
A pair of virtual character devices that simulate a serial terminal connection. The master side is held by the terminal emulator. The slave side is given to the shell. Data written to one end appears as input on the other, with the kernel&#x27;s line discipline processing in between.
&lt;&#x2F;div&gt;
&lt;p&gt;The terminal emulator opens the master side. The shell (and any programs the shell runs) open the slave side. When you type a key in the terminal emulator, the emulator writes the character to the master. The kernel&#x27;s TTY layer processes it and makes it available for reading on the slave. When the shell prints output, it writes to the slave. The kernel passes it to the master, and the terminal emulator renders it on screen.&lt;&#x2F;p&gt;
&lt;p&gt;You can see your current PTY with:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;tty
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will print something like &lt;code&gt;&#x2F;dev&#x2F;pts&#x2F;0&lt;&#x2F;code&gt;. The number increases for each terminal you open. List all active pseudoterminals:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;ls &#x2F;dev&#x2F;pts&#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 16b -- The pseudoterminal pair&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Terminal emulator --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;40&quot; width=&quot;160&quot; height=&quot;80&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;65&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Terminal Emulator&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;85&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(gnome-terminal,&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;99&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;alacritty, xterm)&lt;&#x2F;text&gt;
  &lt;!-- PTY Master --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;55&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;dev&#x2F;ptmx (master)&lt;&#x2F;text&gt;
  &lt;!-- Line discipline --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;100&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;122&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Line Discipline&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;140&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(echo, editing, signals)&lt;&#x2F;text&gt;
  &lt;!-- PTY Slave --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;180&quot; width=&quot;140&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;205&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;dev&#x2F;pts&#x2F;0 (slave)&lt;&#x2F;text&gt;
  &lt;!-- Shell --&gt;
  &lt;rect x=&quot;400&quot; y=&quot;170&quot; width=&quot;160&quot; height=&quot;60&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;195&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;bash (shell)&lt;&#x2F;text&gt;
  &lt;text x=&quot;480&quot; y=&quot;212&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;stdin&#x2F;stdout&#x2F;stderr&lt;&#x2F;text&gt;
  &lt;!-- Keyboard&#x2F;Screen labels --&gt;
&lt;p&gt;&lt;text x=&quot;100&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;keyboard input&lt;&#x2F;text&gt;
&lt;text x=&quot;100&quot; y=&quot;165&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;screen output&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Arrows: emulator &lt;-&gt; master --&gt;
  &lt;line x1=&quot;180&quot; y1=&quot;60&quot; x2=&quot;215&quot; y2=&quot;50&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;212,44 222,50 212,56&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;text x=&quot;198&quot; y=&quot;42&quot; fill=&quot;#FFD700&quot; font-size=&quot;8&quot;&gt;keystrokes&lt;&#x2F;text&gt;
  &lt;line x1=&quot;220&quot; y1=&quot;65&quot; x2=&quot;180&quot; y2=&quot;80&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;183,74 173,80 183,86&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;198&quot; y=&quot;80&quot; fill=&quot;#39D353&quot; font-size=&quot;8&quot;&gt;output&lt;&#x2F;text&gt;
  &lt;!-- Arrows: master &lt;-&gt; line discipline --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;70&quot; x2=&quot;290&quot; y2=&quot;95&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;284,92 290,102 296,92&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
  &lt;!-- Arrows: line discipline &lt;-&gt; slave --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;150&quot; x2=&quot;290&quot; y2=&quot;175&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;284,172 290,182 296,172&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
  &lt;!-- Arrows: slave &lt;-&gt; shell --&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;195&quot; x2=&quot;395&quot; y2=&quot;195&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;392,189 402,195 392,201&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;!-- Kernel boundary --&gt;
  &lt;line x1=&quot;210&quot; y1=&quot;20&quot; x2=&quot;210&quot; y2=&quot;240&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;text x=&quot;115&quot; y=&quot;220&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;userspace&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;240&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;kernel&lt;&#x2F;text&gt;
  &lt;text x=&quot;480&quot; y=&quot;245&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;userspace&lt;&#x2F;text&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;20&quot; x2=&quot;370&quot; y2=&quot;240&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;!-- SSH note --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;255&quot; width=&quot;540&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;275&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;SSH uses the same PTY mechanism -- sshd holds the master, the remote shell gets the slave&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The PTY pair connects a terminal emulator to a shell through the kernel. The line discipline sits in the middle, processing input and output.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-line-discipline&quot;&gt;The Line Discipline&lt;&#x2F;h2&gt;
&lt;p&gt;Between the master and slave sides of the PTY sits the &lt;strong&gt;line discipline&lt;&#x2F;strong&gt; -- a kernel module that processes characters as they flow through the terminal. The line discipline is what makes a terminal feel like a terminal rather than a raw data pipe.&lt;&#x2F;p&gt;
&lt;p&gt;In its default mode (called &lt;strong&gt;canonical mode&lt;&#x2F;strong&gt; or &lt;strong&gt;cooked mode&lt;&#x2F;strong&gt;), the line discipline provides:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Line editing.&lt;&#x2F;strong&gt; When you type a character and press backspace, the line discipline removes the last character. You are editing a line buffer inside the kernel. The program on the other end does not see any of this -- it only receives a complete line when you press Enter.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Echo.&lt;&#x2F;strong&gt; When you type a character, the line discipline sends a copy back to the terminal so you can see what you typed. This is why you see your own keystrokes. Turn off echo (as &lt;code&gt;passwd&lt;&#x2F;code&gt; does), and you type blind.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Signal generation.&lt;&#x2F;strong&gt; Certain key combinations are intercepted by the line discipline and converted to signals:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Ctrl+C generates SIGINT (interrupt the foreground process)&lt;&#x2F;li&gt;
&lt;li&gt;Ctrl+Z generates SIGTSTP (suspend the foreground process)&lt;&#x2F;li&gt;
&lt;li&gt;Ctrl+\ generates SIGQUIT (quit with core dump)&lt;&#x2F;li&gt;
&lt;li&gt;Ctrl+D on an empty line signals end-of-file&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These key bindings are not hard-coded -- they are configurable with the &lt;code&gt;stty&lt;&#x2F;code&gt; command. You can see the current settings:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;stty -a
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;remember&quot;&gt;
The line discipline is the invisible layer that makes terminals usable. It handles line editing, character echo, and signal generation. Programs can disable it (raw mode) when they need to handle every keystroke themselves.
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;raw-mode&quot;&gt;Raw Mode&lt;&#x2F;h3&gt;
&lt;p&gt;Some programs need to handle every keystroke directly -- text editors like vim, interactive programs like top, and anything that uses arrow keys for navigation. These programs switch the terminal to &lt;strong&gt;raw mode&lt;&#x2F;strong&gt; (technically, they disable canonical mode and echo). In raw mode, the line discipline does nothing: every keystroke is passed immediately to the program without buffering, editing, or signal translation.&lt;&#x2F;p&gt;
&lt;p&gt;This is why pressing Ctrl+C in vim does not kill vim. Vim has put the terminal in raw mode and handles Ctrl+C itself.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-keystrokes-reach-your-shell&quot;&gt;How Keystrokes Reach Your Shell&lt;&#x2F;h2&gt;
&lt;p&gt;Let us trace what happens when you press the letter &quot;a&quot; in a terminal emulator:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Your operating system&#x27;s window manager detects the key press and sends a key event to the terminal emulator application.&lt;&#x2F;li&gt;
&lt;li&gt;The terminal emulator translates the key event to the byte &lt;code&gt;0x61&lt;&#x2F;code&gt; (ASCII for &quot;a&quot;).&lt;&#x2F;li&gt;
&lt;li&gt;The terminal emulator writes &lt;code&gt;0x61&lt;&#x2F;code&gt; to the PTY master (&lt;code&gt;&#x2F;dev&#x2F;ptmx&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;The kernel&#x27;s line discipline receives the byte. In canonical mode, it adds it to the line buffer and echoes it back to the master (so the terminal emulator can display it).&lt;&#x2F;li&gt;
&lt;li&gt;When you press Enter (&lt;code&gt;0x0A&lt;&#x2F;code&gt;), the line discipline marks the line as complete.&lt;&#x2F;li&gt;
&lt;li&gt;The shell, reading from the PTY slave (&lt;code&gt;&#x2F;dev&#x2F;pts&#x2F;0&lt;&#x2F;code&gt;), receives the complete line.&lt;&#x2F;li&gt;
&lt;li&gt;The shell processes the command and writes its output to the PTY slave.&lt;&#x2F;li&gt;
&lt;li&gt;The output passes through the line discipline (which does minimal processing on output) to the PTY master.&lt;&#x2F;li&gt;
&lt;li&gt;The terminal emulator reads the output from the master and renders it on screen.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 16c -- Journey of a keystroke&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 380&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;380&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Steps as a vertical flow --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;15&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;35&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;1. Key press detected&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;60&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;80&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2. Encode to ASCII 0x61&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;105&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;125&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;3. Write to PTY master&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;150&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;170&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;4. Line discipline buffers&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;195&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;215&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;5. Enter: line complete&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;240&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;260&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;6. Shell reads from slave&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;285&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;305&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;7. Shell writes output&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;330&quot; width=&quot;180&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;350&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;8. Emulator renders text&lt;&#x2F;text&gt;
  &lt;!-- Arrows between steps --&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;45&quot; x2=&quot;130&quot; y2=&quot;57&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;90&quot; x2=&quot;130&quot; y2=&quot;102&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;135&quot; x2=&quot;130&quot; y2=&quot;147&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;180&quot; x2=&quot;130&quot; y2=&quot;192&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;225&quot; x2=&quot;130&quot; y2=&quot;237&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;270&quot; x2=&quot;130&quot; y2=&quot;282&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;315&quot; x2=&quot;130&quot; y2=&quot;327&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Echo path --&gt;
  &lt;rect x=&quot;300&quot; y=&quot;105&quot; width=&quot;250&quot; height=&quot;120&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;425&quot; y=&quot;128&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Echo Path&lt;&#x2F;text&gt;
  &lt;text x=&quot;425&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Line discipline echoes each&lt;&#x2F;text&gt;
  &lt;text x=&quot;425&quot; y=&quot;165&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;character back to the master&lt;&#x2F;text&gt;
  &lt;text x=&quot;425&quot; y=&quot;180&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;so the emulator can display it&lt;&#x2F;text&gt;
  &lt;text x=&quot;425&quot; y=&quot;195&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;BEFORE the shell sees anything&lt;&#x2F;text&gt;
  &lt;!-- Arrow from step 4 to echo --&gt;
  &lt;line x1=&quot;220&quot; y1=&quot;165&quot; x2=&quot;295&quot; y2=&quot;165&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;polygon points=&quot;292,159 302,165 292,171&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
  &lt;!-- Zone brackets on the right side --&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;15&quot; x2=&quot;255&quot; y2=&quot;15&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;255&quot; y1=&quot;15&quot; x2=&quot;255&quot; y2=&quot;90&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;90&quot; x2=&quot;255&quot; y2=&quot;90&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;268&quot; y=&quot;57&quot; fill=&quot;#FFD700&quot; font-size=&quot;8&quot;&gt;emulator&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;105&quot; x2=&quot;255&quot; y2=&quot;105&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;255&quot; y1=&quot;105&quot; x2=&quot;255&quot; y2=&quot;225&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;225&quot; x2=&quot;255&quot; y2=&quot;225&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;268&quot; y=&quot;162&quot; fill=&quot;#FF6600&quot; font-size=&quot;8&quot;&gt;kernel&lt;&#x2F;text&gt;
  &lt;text x=&quot;268&quot; y=&quot;174&quot; fill=&quot;#FF6600&quot; font-size=&quot;8&quot;&gt;(TTY layer)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;240&quot; x2=&quot;255&quot; y2=&quot;240&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;255&quot; y1=&quot;240&quot; x2=&quot;255&quot; y2=&quot;315&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;315&quot; x2=&quot;255&quot; y2=&quot;315&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;268&quot; y=&quot;275&quot; fill=&quot;#39D353&quot; font-size=&quot;8&quot;&gt;shell&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;330&quot; x2=&quot;255&quot; y2=&quot;330&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;255&quot; y1=&quot;330&quot; x2=&quot;255&quot; y2=&quot;360&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;360&quot; x2=&quot;255&quot; y2=&quot;360&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;268&quot; y=&quot;349&quot; fill=&quot;#FFD700&quot; font-size=&quot;8&quot;&gt;emulator&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A keystroke makes a round trip: from the emulator to the kernel, through the line discipline, to the shell, and back. Echo happens before the shell ever sees the character.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;terminal-escape-codes&quot;&gt;Terminal Escape Codes&lt;&#x2F;h2&gt;
&lt;p&gt;A terminal does more than display plain text. It can position the cursor, change text color, clear the screen, and scroll regions. It does all of this through &lt;strong&gt;escape sequences&lt;&#x2F;strong&gt; -- special byte sequences that the terminal interprets as commands rather than text.&lt;&#x2F;p&gt;
&lt;p&gt;An escape sequence begins with the ESC character (byte &lt;code&gt;0x1B&lt;&#x2F;code&gt;), followed by &lt;code&gt;[&lt;&#x2F;code&gt;, then parameters and a command letter. These are called &lt;strong&gt;ANSI escape codes&lt;&#x2F;strong&gt; because they were standardized by ANSI (the American National Standards Institute) in the 1970s.&lt;&#x2F;p&gt;
&lt;p&gt;Some examples:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Sequence&lt;&#x2F;th&gt;&lt;th&gt;Effect&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ESC[2J&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Clear the entire screen&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ESC[H&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Move cursor to top-left&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ESC[31m&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Set text color to red&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ESC[0m&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Reset all formatting&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ESC[10;20H&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Move cursor to row 10, column 20&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ESC[1A&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Move cursor up one line&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;When a program like &lt;code&gt;ls --color&lt;&#x2F;code&gt; outputs colored filenames, it is embedding these escape sequences in its output. The terminal emulator intercepts them and changes the rendering instead of displaying the raw bytes.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Escape sequence&lt;&#x2F;strong&gt;
A series of bytes beginning with ESC (0x1B) that instructs a terminal to perform an action like moving the cursor, changing colors, or clearing the screen. Programs use these to create interactive text interfaces.
&lt;&#x2F;div&gt;
&lt;p&gt;This is also why piping colored output to a file produces garbled-looking text -- the file contains the raw escape sequences, which only make sense to a terminal.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;# This shows escape codes as visible text
ls --color=always | cat -v
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;the-terminal-and-job-control&quot;&gt;The Terminal and Job Control&lt;&#x2F;h2&gt;
&lt;p&gt;The terminal layer is deeply connected to process management. Each terminal has a concept of a &lt;strong&gt;foreground process group&lt;&#x2F;strong&gt; -- the set of processes currently allowed to read from the terminal and receive keyboard signals.&lt;&#x2F;p&gt;
&lt;p&gt;When you press Ctrl+C, the kernel does not send SIGINT to every process. It sends it to the foreground process group of the controlling terminal. When you press Ctrl+Z, SIGTSTP goes to the foreground process group.&lt;&#x2F;p&gt;
&lt;p&gt;This is how job control works in the shell. When you run a command, the shell puts it in the foreground. When you press Ctrl+Z, it gets stopped. When you type &lt;code&gt;bg&lt;&#x2F;code&gt;, the shell moves it to a background process group. Background processes that try to read from the terminal receive SIGTTIN and get stopped -- they are not allowed to compete with the foreground for terminal input.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 16d -- Terminal sessions and process groups&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 260&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;260&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Terminal device --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;90&quot; width=&quot;120&quot; height=&quot;60&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;115&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;dev&#x2F;pts&#x2F;0&lt;&#x2F;text&gt;
  &lt;text x=&quot;80&quot; y=&quot;132&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;controlling tty&lt;&#x2F;text&gt;
  &lt;!-- Session --&gt;
  &lt;rect x=&quot;170&quot; y=&quot;15&quot; width=&quot;390&quot; height=&quot;230&quot; rx=&quot;6&quot; fill=&quot;rgba(0,191,255,0.05)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;text x=&quot;365&quot; y=&quot;35&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Session (SID 1401)&lt;&#x2F;text&gt;
  &lt;!-- Session leader --&gt;
  &lt;rect x=&quot;190&quot; y=&quot;50&quot; width=&quot;130&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;255&quot; y=&quot;72&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;bash (1401) leader&lt;&#x2F;text&gt;
  &lt;!-- Foreground group --&gt;
  &lt;rect x=&quot;190&quot; y=&quot;100&quot; width=&quot;170&quot; height=&quot;70&quot; rx=&quot;4&quot; fill=&quot;rgba(57,211,83,0.08)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;275&quot; y=&quot;118&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Foreground group&lt;&#x2F;text&gt;
  &lt;rect x=&quot;200&quot; y=&quot;130&quot; width=&quot;70&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;149&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;grep&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;130&quot; width=&quot;70&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;315&quot; y=&quot;149&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;sort&lt;&#x2F;text&gt;
  &lt;!-- Background group --&gt;
  &lt;rect x=&quot;380&quot; y=&quot;100&quot; width=&quot;170&quot; height=&quot;70&quot; rx=&quot;4&quot; fill=&quot;rgba(255,102,0,0.08)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;465&quot; y=&quot;118&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Background group&lt;&#x2F;text&gt;
  &lt;rect x=&quot;410&quot; y=&quot;130&quot; width=&quot;110&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;465&quot; y=&quot;149&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;make -j4 &amp;&lt;&#x2F;text&gt;
  &lt;!-- Arrow from terminal to foreground --&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;110&quot; x2=&quot;185&quot; y2=&quot;110&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;182,104 192,110 182,116&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;162&quot; y=&quot;100&quot; fill=&quot;#39D353&quot; font-size=&quot;8&quot;&gt;Ctrl+C&lt;&#x2F;text&gt;
  &lt;!-- X from terminal to background --&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;130&quot; x2=&quot;375&quot; y2=&quot;145&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;text x=&quot;258&quot; y=&quot;202&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Background cannot read from terminal (SIGTTIN)&lt;&#x2F;text&gt;
  &lt;!-- Signals label --&gt;
&lt;p&gt;&lt;text x=&quot;162&quot; y=&quot;82&quot; fill=&quot;#FFD700&quot; font-size=&quot;8&quot;&gt;SIGINT&lt;&#x2F;text&gt;
&lt;text x=&quot;162&quot; y=&quot;150&quot; fill=&quot;#FFD700&quot; font-size=&quot;8&quot;&gt;SIGTSTP&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A terminal session contains one foreground and zero or more background process groups. Keyboard signals only reach the foreground group.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;div class=&quot;remember&quot;&gt;
The TTY subsystem is not just about displaying text. It manages which processes can read from the terminal, delivers keyboard-generated signals, and provides line editing. Understanding this layer explains why Ctrl+C, Ctrl+Z, and job control work the way they do.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;ssh-and-remote-terminals&quot;&gt;SSH and Remote Terminals&lt;&#x2F;h2&gt;
&lt;p&gt;SSH uses the same PTY mechanism. When you SSH into a remote machine, the sshd daemon on the remote side allocates a PTY pair. sshd holds the master, and the remote shell gets the slave. Your keystrokes travel encrypted over the network to sshd, which writes them to the master. Output travels back the same way.&lt;&#x2F;p&gt;
&lt;p&gt;This is why interactive programs work over SSH -- the remote shell sees a real PTY slave and behaves exactly as if you were sitting at a local terminal. The &lt;code&gt;TERM&lt;&#x2F;code&gt; environment variable (usually set to &lt;code&gt;xterm-256color&lt;&#x2F;code&gt; or similar) tells programs which escape sequences the terminal understands.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;inspecting-your-terminal&quot;&gt;Inspecting Your Terminal&lt;&#x2F;h2&gt;
&lt;p&gt;A few commands for examining the terminal system:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;tty                  # Print your current terminal device
stty -a              # Show all terminal settings
who                  # Show logged-in users and their terminals
w                    # Show who is logged in and what they are doing
ls -la &#x2F;dev&#x2F;pts&#x2F;     # List active pseudoterminals
echo $TERM           # Show the terminal type
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;stty&lt;&#x2F;code&gt; command is particularly useful. It shows the current line discipline settings: which characters trigger signals, whether echo is on, the terminal dimensions (rows and columns), and the baud rate (a historical artifact that is always 38400 for PTYs).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-this-still-matters&quot;&gt;Why This Still Matters&lt;&#x2F;h2&gt;
&lt;p&gt;Every time you open a terminal, type a command, press Ctrl+C to interrupt something, or SSH into a server, the TTY subsystem is doing the work. The abstraction is so good that you rarely think about it. But when something goes wrong -- when a program leaves your terminal in a broken state, when Ctrl+C does not work, when characters display as garbage -- understanding the PTY, the line discipline, and escape codes gives you the knowledge to fix it.&lt;&#x2F;p&gt;
&lt;p&gt;If your terminal ever gets into a bad state (no echo, garbled display), the fix is:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;reset
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This sends the terminal reset escape sequence and restores the line discipline to sane defaults. It works because it operates at the same level as the problem -- the TTY layer.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;17-users-groups-and-permissions&#x2F;&quot;&gt;Users, Groups, and Permissions&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Process Model</title>
        <published>2025-01-19T00:00:00+00:00</published>
        <updated>2025-01-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/15-the-process-model/"/>
        <id>https://t34ch.tech/coldboot/articles/15-the-process-model/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/15-the-process-model/">&lt;p&gt;Every program running on your computer right now -- your browser, your text editor, the background service checking for software updates -- is a process. A process is the kernel&#x27;s abstraction for &quot;a running program.&quot; It is the unit of work that the operating system tracks, schedules, and controls.&lt;&#x2F;p&gt;
&lt;p&gt;The previous article described PID 1, the first process. But how does PID 1 start everything else? How does any process start another? The answer lies in three system calls that have defined Unix process management since the 1970s: &lt;code&gt;fork()&lt;&#x2F;code&gt;, &lt;code&gt;exec()&lt;&#x2F;code&gt;, and &lt;code&gt;wait()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-a-process-is&quot;&gt;What a Process Is&lt;&#x2F;h2&gt;
&lt;p&gt;Think of a process as a sealed envelope. Inside the envelope is everything needed to run a program: the program&#x27;s code, its current state, the data it is working on, and a record of which files it has open. The kernel keeps a table of all these envelopes and decides which one gets to use the CPU at any given moment.&lt;&#x2F;p&gt;
&lt;p&gt;Each process has:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;PID&lt;&#x2F;strong&gt; -- a unique integer identifier&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;strong&gt;parent PID (PPID)&lt;&#x2F;strong&gt; -- the PID of the process that created it&lt;&#x2F;li&gt;
&lt;li&gt;A &lt;strong&gt;memory space&lt;&#x2F;strong&gt; -- its own private region of RAM&lt;&#x2F;li&gt;
&lt;li&gt;An &lt;strong&gt;execution state&lt;&#x2F;strong&gt; -- running, sleeping, stopped, or zombie&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Open file descriptors&lt;&#x2F;strong&gt; -- references to files, sockets, and pipes&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Credentials&lt;&#x2F;strong&gt; -- the user and group it runs as&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Process&lt;&#x2F;strong&gt;
An instance of a running program. The kernel assigns each process its own memory space, a unique PID, and a set of resources. Multiple processes can run the same program simultaneously -- each is an independent instance.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 15a -- Anatomy of a process&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 320&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;320&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Process envelope --&gt;
  &lt;rect x=&quot;120&quot; y=&quot;15&quot; width=&quot;340&quot; height=&quot;290&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;40&quot; fill=&quot;#FFD700&quot; font-size=&quot;14&quot; text-anchor=&quot;middle&quot;&gt;Process (PID 4827)&lt;&#x2F;text&gt;
  &lt;!-- Code segment --&gt;
  &lt;rect x=&quot;145&quot; y=&quot;55&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;215&quot; y=&quot;73&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Program Code&lt;&#x2F;text&gt;
  &lt;text x=&quot;215&quot; y=&quot;90&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(text segment)&lt;&#x2F;text&gt;
  &lt;!-- Data segment --&gt;
  &lt;rect x=&quot;295&quot; y=&quot;55&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;365&quot; y=&quot;73&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Data&lt;&#x2F;text&gt;
  &lt;text x=&quot;365&quot; y=&quot;90&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(heap + stack)&lt;&#x2F;text&gt;
  &lt;!-- State info --&gt;
  &lt;rect x=&quot;145&quot; y=&quot;115&quot; width=&quot;290&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;135&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;PID: 4827&lt;&#x2F;text&gt;
  &lt;text x=&quot;270&quot; y=&quot;135&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;PPID: 1203&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;135&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;State: Running&lt;&#x2F;text&gt;
  &lt;text x=&quot;160&quot; y=&quot;149&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;UID: 1000  GID: 1000  Nice: 0&lt;&#x2F;text&gt;
  &lt;!-- File descriptors --&gt;
  &lt;rect x=&quot;145&quot; y=&quot;170&quot; width=&quot;290&quot; height=&quot;60&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;188&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Open File Descriptors&lt;&#x2F;text&gt;
  &lt;text x=&quot;160&quot; y=&quot;205&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot;&gt;fd 0: stdin  (terminal)&lt;&#x2F;text&gt;
  &lt;text x=&quot;160&quot; y=&quot;218&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot;&gt;fd 1: stdout (terminal)&lt;&#x2F;text&gt;
  &lt;text x=&quot;330&quot; y=&quot;205&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot;&gt;fd 2: stderr (terminal)&lt;&#x2F;text&gt;
  &lt;text x=&quot;330&quot; y=&quot;218&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot;&gt;fd 3: &#x2F;var&#x2F;log&#x2F;app.log&lt;&#x2F;text&gt;
  &lt;!-- Registers --&gt;
  &lt;rect x=&quot;145&quot; y=&quot;245&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;215&quot; y=&quot;265&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;CPU Registers&lt;&#x2F;text&gt;
  &lt;text x=&quot;215&quot; y=&quot;280&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(saved on context switch)&lt;&#x2F;text&gt;
  &lt;!-- Signal handlers --&gt;
  &lt;rect x=&quot;295&quot; y=&quot;245&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;365&quot; y=&quot;265&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Signal Handlers&lt;&#x2F;text&gt;
  &lt;text x=&quot;365&quot; y=&quot;280&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(SIGTERM, SIGINT, ...)&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Each process is a self-contained unit with its own code, data, state, file descriptors, and saved CPU registers. The kernel manages all of these.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-process-table&quot;&gt;The Process Table&lt;&#x2F;h2&gt;
&lt;p&gt;The kernel maintains a data structure called the &lt;strong&gt;process table&lt;&#x2F;strong&gt; (internally, a list of &lt;code&gt;task_struct&lt;&#x2F;code&gt; structures in Linux). Every process on the system has an entry. You can see a snapshot of it with the &lt;code&gt;ps&lt;&#x2F;code&gt; command:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;ps aux
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This shows every process, its PID, its parent, how much CPU and memory it uses, and the command that started it. On a typical desktop system, you will see hundreds of entries. On a busy server, thousands.&lt;&#x2F;p&gt;
&lt;p&gt;Each entry costs memory. The kernel allocates a &lt;code&gt;task_struct&lt;&#x2F;code&gt; (about 6 KB on a 64-bit Linux system) plus the process&#x27;s page tables and kernel stack. This is why creating processes is not free -- though on modern systems, the overhead is small enough that you rarely worry about it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fork-cloning-a-process&quot;&gt;fork(): Cloning a Process&lt;&#x2F;h2&gt;
&lt;p&gt;The fundamental operation in Unix process creation is &lt;code&gt;fork()&lt;&#x2F;code&gt;. When a process calls &lt;code&gt;fork()&lt;&#x2F;code&gt;, the kernel creates a near-exact copy of the calling process. The new process -- called the &lt;strong&gt;child&lt;&#x2F;strong&gt; -- gets a new PID, but everything else is a duplicate: the same code, the same data, the same open files, the same position in the program.&lt;&#x2F;p&gt;
&lt;p&gt;Think of it like photocopying a document. You now have two copies that are identical at the moment of copying, but changes to one do not affect the other.&lt;&#x2F;p&gt;
&lt;p&gt;After &lt;code&gt;fork()&lt;&#x2F;code&gt; returns, two processes are running the same code at the same point. The only difference is the return value: the parent receives the child&#x27;s PID, and the child receives zero. This is how each process knows which one it is.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;c&quot;&gt;pid_t pid = fork();

if (pid == 0) {
    &#x2F;&#x2F; This is the child process
    printf(&amp;quot;I am the child, PID %d\n&amp;quot;, getpid());
} else {
    &#x2F;&#x2F; This is the parent process
    printf(&amp;quot;I am the parent, child PID is %d\n&amp;quot;, pid);
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: fork()&lt;&#x2F;strong&gt;
A system call that creates a new process by duplicating the calling process. The new child process has its own PID and memory space, but starts as an exact copy of its parent. Modern Linux uses copy-on-write to make this efficient.
&lt;&#x2F;div&gt;
&lt;p&gt;In practice, the kernel does not actually copy all the memory immediately. It uses a technique called &lt;strong&gt;copy-on-write (COW)&lt;&#x2F;strong&gt;: both parent and child share the same physical memory pages, marked read-only. Only when one of them tries to write does the kernel copy just the affected page. This makes &lt;code&gt;fork()&lt;&#x2F;code&gt; fast even for processes using gigabytes of memory.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 15b -- fork() creates a child process&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Before label --&gt;
&lt;p&gt;&lt;text x=&quot;145&quot; y=&quot;25&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Before fork()&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;25&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;After fork()&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Divider --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;10&quot; x2=&quot;290&quot; y2=&quot;270&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;!-- Before: single process --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;45&quot; width=&quot;170&quot; height=&quot;100&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;70&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;PID 500&lt;&#x2F;text&gt;
  &lt;text x=&quot;145&quot; y=&quot;90&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;code + data&lt;&#x2F;text&gt;
  &lt;text x=&quot;145&quot; y=&quot;110&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;memory: 40 MB&lt;&#x2F;text&gt;
  &lt;text x=&quot;145&quot; y=&quot;130&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;3 open files&lt;&#x2F;text&gt;
  &lt;!-- After: parent --&gt;
  &lt;rect x=&quot;310&quot; y=&quot;45&quot; width=&quot;150&quot; height=&quot;90&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;385&quot; y=&quot;68&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Parent PID 500&lt;&#x2F;text&gt;
  &lt;text x=&quot;385&quot; y=&quot;88&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;fork() returned 501&lt;&#x2F;text&gt;
  &lt;text x=&quot;385&quot; y=&quot;108&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;code + data (shared)&lt;&#x2F;text&gt;
  &lt;!-- After: child --&gt;
  &lt;rect x=&quot;310&quot; y=&quot;160&quot; width=&quot;150&quot; height=&quot;90&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;385&quot; y=&quot;183&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Child PID 501&lt;&#x2F;text&gt;
  &lt;text x=&quot;385&quot; y=&quot;203&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;fork() returned 0&lt;&#x2F;text&gt;
  &lt;text x=&quot;385&quot; y=&quot;223&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;code + data (shared)&lt;&#x2F;text&gt;
  &lt;!-- COW shared memory --&gt;
  &lt;rect x=&quot;480&quot; y=&quot;100&quot; width=&quot;80&quot; height=&quot;100&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;text x=&quot;520&quot; y=&quot;140&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Shared&lt;&#x2F;text&gt;
  &lt;text x=&quot;520&quot; y=&quot;155&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;pages&lt;&#x2F;text&gt;
  &lt;text x=&quot;520&quot; y=&quot;170&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(COW)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;460&quot; y1=&quot;100&quot; x2=&quot;480&quot; y2=&quot;120&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;line x1=&quot;460&quot; y1=&quot;200&quot; x2=&quot;480&quot; y2=&quot;180&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,2&quot;&#x2F;&gt;
  &lt;!-- Arrow showing fork --&gt;
  &lt;line x1=&quot;230&quot; y1=&quot;95&quot; x2=&quot;305&quot; y2=&quot;85&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;300,79 312,85 300,91&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;line x1=&quot;230&quot; y1=&quot;95&quot; x2=&quot;305&quot; y2=&quot;200&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;300,195 312,201 302,207&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;260&quot; y=&quot;140&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;fork()&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;fork() splits one process into two. The parent and child share physical memory through copy-on-write until one of them modifies a page.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;exec-replacing-a-process&quot;&gt;exec(): Replacing a Process&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;fork()&lt;&#x2F;code&gt; alone just creates copies. To run a different program, a process calls one of the &lt;code&gt;exec()&lt;&#x2F;code&gt; family of functions (&lt;code&gt;execve&lt;&#x2F;code&gt;, &lt;code&gt;execl&lt;&#x2F;code&gt;, &lt;code&gt;execvp&lt;&#x2F;code&gt;, etc.). This replaces the process&#x27;s code, data, and stack with a new program loaded from disk. The PID stays the same. The open file descriptors stay the same (unless marked close-on-exec). But the running program is entirely different.&lt;&#x2F;p&gt;
&lt;p&gt;This is the standard Unix pattern for starting a new program:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The parent calls &lt;code&gt;fork()&lt;&#x2F;code&gt; to create a child.&lt;&#x2F;li&gt;
&lt;li&gt;The child calls &lt;code&gt;exec()&lt;&#x2F;code&gt; to replace itself with the new program.&lt;&#x2F;li&gt;
&lt;li&gt;The parent continues running.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This two-step approach seems roundabout, but it is powerful. Between the &lt;code&gt;fork()&lt;&#x2F;code&gt; and the &lt;code&gt;exec()&lt;&#x2F;code&gt;, the child can rearrange its file descriptors, change its working directory, drop privileges, or set up any other environment the new program needs -- all without affecting the parent.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The fork-then-exec pattern is the foundation of process creation in Unix. fork() creates a copy, exec() replaces it with a new program. This two-step design lets the child set up its environment before the new program starts.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;wait-collecting-the-dead&quot;&gt;wait(): Collecting the Dead&lt;&#x2F;h2&gt;
&lt;p&gt;When a child process exits, it does not vanish immediately. The kernel retains its exit status -- a small integer indicating whether it succeeded (0) or failed (nonzero) -- in the process table. The parent must call &lt;code&gt;wait()&lt;&#x2F;code&gt; or &lt;code&gt;waitpid()&lt;&#x2F;code&gt; to read this status and release the entry.&lt;&#x2F;p&gt;
&lt;p&gt;This is the contract: the parent that created the child is responsible for collecting its exit status. Until it does, the dead child remains in the process table as a &lt;strong&gt;zombie&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;c&quot;&gt;pid_t pid = fork();

if (pid == 0) {
    &#x2F;&#x2F; Child does its work, then exits
    exit(0);
} else {
    &#x2F;&#x2F; Parent waits for the child to finish
    int status;
    waitpid(pid, &amp;amp;status, 0);
    printf(&amp;quot;Child exited with status %d\n&amp;quot;, WEXITSTATUS(status));
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;process-states&quot;&gt;Process States&lt;&#x2F;h2&gt;
&lt;p&gt;A process is always in one of several states. The kernel tracks the current state and transitions the process between them:&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 15c -- Process state transitions&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Created --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;85&quot; y=&quot;65&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Created&lt;&#x2F;text&gt;
  &lt;!-- Ready --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;255&quot; y=&quot;65&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Ready&lt;&#x2F;text&gt;
  &lt;!-- Running --&gt;
  &lt;rect x=&quot;370&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;425&quot; y=&quot;65&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Running&lt;&#x2F;text&gt;
  &lt;!-- Sleeping --&gt;
  &lt;rect x=&quot;370&quot; y=&quot;150&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;425&quot; y=&quot;175&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Sleeping&lt;&#x2F;text&gt;
  &lt;!-- Stopped --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;150&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;255&quot; y=&quot;175&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Stopped&lt;&#x2F;text&gt;
  &lt;!-- Zombie --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;260&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;255&quot; y=&quot;285&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Zombie&lt;&#x2F;text&gt;
  &lt;!-- Reaped --&gt;
  &lt;rect x=&quot;370&quot; y=&quot;260&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;425&quot; y=&quot;285&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Removed&lt;&#x2F;text&gt;
  &lt;!-- Arrows --&gt;
  &lt;!-- Created -&gt; Ready --&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;60&quot; x2=&quot;195&quot; y2=&quot;60&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;192,54 202,60 192,66&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
  &lt;text x=&quot;168&quot; y=&quot;52&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;fork()&lt;&#x2F;text&gt;
  &lt;!-- Ready -&gt; Running --&gt;
  &lt;line x1=&quot;310&quot; y1=&quot;52&quot; x2=&quot;365&quot; y2=&quot;52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;362,46 372,52 362,58&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;338&quot; y=&quot;44&quot; fill=&quot;#39D353&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;scheduled&lt;&#x2F;text&gt;
  &lt;!-- Running -&gt; Ready (preempted) --&gt;
  &lt;line x1=&quot;365&quot; y1=&quot;72&quot; x2=&quot;310&quot; y2=&quot;72&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;313,66 303,72 313,78&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;text x=&quot;338&quot; y=&quot;86&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;preempted&lt;&#x2F;text&gt;
  &lt;!-- Running -&gt; Sleeping --&gt;
  &lt;line x1=&quot;425&quot; y1=&quot;80&quot; x2=&quot;425&quot; y2=&quot;145&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;419,142 425,152 431,142&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;text x=&quot;450&quot; y=&quot;118&quot; fill=&quot;#FFD700&quot; font-size=&quot;8&quot;&gt;I&#x2F;O wait&lt;&#x2F;text&gt;
  &lt;!-- Sleeping -&gt; Ready --&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;160&quot; x2=&quot;310&quot; y2=&quot;65&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;314,61 308,71 318,68&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;text x=&quot;355&quot; y=&quot;125&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot;&gt;event&lt;&#x2F;text&gt;
  &lt;!-- Running -&gt; Stopped --&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;65&quot; x2=&quot;310&quot; y2=&quot;155&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;314,151 308,161 318,158&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
  &lt;text x=&quot;325&quot; y=&quot;100&quot; fill=&quot;#FF6600&quot; font-size=&quot;8&quot;&gt;SIGSTOP&lt;&#x2F;text&gt;
  &lt;!-- Stopped -&gt; Ready --&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;150&quot; x2=&quot;240&quot; y2=&quot;85&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;234,88 240,78 246,88&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;text x=&quot;220&quot; y=&quot;120&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot;&gt;SIGCONT&lt;&#x2F;text&gt;
  &lt;!-- Running -&gt; Zombie --&gt;
  &lt;path d=&quot;M 425 80 L 425 230 L 310 260&quot; fill=&quot;none&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;313,254 305,263 313,266&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;445&quot; y=&quot;230&quot; fill=&quot;#C0392B&quot; font-size=&quot;8&quot;&gt;exit()&lt;&#x2F;text&gt;
  &lt;!-- Zombie -&gt; Removed --&gt;
  &lt;line x1=&quot;310&quot; y1=&quot;280&quot; x2=&quot;365&quot; y2=&quot;280&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;362,274 372,280 362,286&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;text x=&quot;338&quot; y=&quot;272&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot;&gt;wait()&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A process moves through these states during its lifetime. The scheduler decides which ready process gets the CPU. A zombie exists only to hold an exit status until the parent reads it.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;&lt;strong&gt;Running&lt;&#x2F;strong&gt; -- currently executing on a CPU core. On a single-core system, only one process can be running at a time. On a multi-core system, one per core.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Ready (Runnable)&lt;&#x2F;strong&gt; -- able to run, waiting for the scheduler to give it a CPU time slice.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Sleeping&lt;&#x2F;strong&gt; -- waiting for something external. This is the most common state. A process reading from a network socket sleeps until data arrives. A process waiting for disk I&#x2F;O sleeps until the read completes. There are two variants: interruptible sleep (can be woken by signals) and uninterruptible sleep (cannot).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Stopped&lt;&#x2F;strong&gt; -- paused by a signal, typically SIGSTOP or SIGTSTP (what happens when you press Ctrl+Z in a terminal). The process remains in memory but does not execute. SIGCONT resumes it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Zombie&lt;&#x2F;strong&gt; -- the process has exited, but its parent has not yet called &lt;code&gt;wait()&lt;&#x2F;code&gt;. The process table entry remains so the parent can read the exit status.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zombies-and-orphans&quot;&gt;Zombies and Orphans&lt;&#x2F;h2&gt;
&lt;p&gt;These two situations arise from the parent-child relationship.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zombie-processes&quot;&gt;Zombie Processes&lt;&#x2F;h3&gt;
&lt;p&gt;A zombie is a process that has finished executing but still has an entry in the process table. The entry is tiny -- just enough to store the PID and exit status -- but it is still a slot in the kernel&#x27;s table. A few zombies are harmless. Thousands of them can exhaust the PID space.&lt;&#x2F;p&gt;
&lt;p&gt;You can spot zombies in &lt;code&gt;ps&lt;&#x2F;code&gt; output by the state letter &lt;code&gt;Z&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;ps aux | grep Z
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The fix is always the same: the parent must call &lt;code&gt;wait()&lt;&#x2F;code&gt;. If the parent is your code, fix it. If the parent is a third-party program, the only remedy is to kill the parent. When the parent dies, the zombies are adopted by PID 1, which reaps them immediately.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;orphan-processes&quot;&gt;Orphan Processes&lt;&#x2F;h3&gt;
&lt;p&gt;An orphan is a process whose parent has exited. The kernel does not allow a process to have no parent, so it reassigns the orphan to PID 1 (the init process). PID 1 is required to periodically call &lt;code&gt;wait()&lt;&#x2F;code&gt; for any adopted children, which prevents orphans from becoming permanent zombies.&lt;&#x2F;p&gt;
&lt;p&gt;This is one of PID 1&#x27;s special responsibilities, as we discussed in the previous article. If PID 1 fails to reap orphaned zombies, the system slowly accumulates dead process entries that can never be cleaned up.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Zombie process&lt;&#x2F;strong&gt;
A process that has exited but whose parent has not yet collected its exit status via wait(). It occupies a slot in the process table but consumes no CPU or memory beyond that small entry. The name comes from the fact that it is dead but still present.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-process-tree&quot;&gt;The Process Tree&lt;&#x2F;h2&gt;
&lt;p&gt;Because every process (except PID 1) has a parent, the entire set of processes forms a tree. PID 1 is the root. You can see this tree with:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;pstree -p
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On a typical system, the tree looks something like this: PID 1 (systemd) starts a login manager, which starts your desktop session, which starts a terminal emulator, which starts your shell, which starts the commands you type. Each layer is a parent-child relationship created by fork() and exec().&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 15d -- The process tree&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- PID 1 --&gt;
  &lt;rect x=&quot;230&quot; y=&quot;15&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;38&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;systemd (1)&lt;&#x2F;text&gt;
  &lt;!-- Level 2 --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;85&quot; width=&quot;120&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;105&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;sshd (480)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;180&quot; y=&quot;85&quot; width=&quot;120&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;240&quot; y=&quot;105&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;gdm (512)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;330&quot; y=&quot;85&quot; width=&quot;120&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;390&quot; y=&quot;105&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;cron (495)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;465&quot; y=&quot;85&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;515&quot; y=&quot;105&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;nginx (520)&lt;&#x2F;text&gt;
  &lt;!-- Lines from PID 1 --&gt;
  &lt;line x1=&quot;260&quot; y1=&quot;50&quot; x2=&quot;90&quot; y2=&quot;85&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;280&quot; y1=&quot;50&quot; x2=&quot;240&quot; y2=&quot;85&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;310&quot; y1=&quot;50&quot; x2=&quot;390&quot; y2=&quot;85&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;330&quot; y1=&quot;50&quot; x2=&quot;515&quot; y2=&quot;85&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Level 3 from sshd --&gt;
  &lt;rect x=&quot;15&quot; y=&quot;155&quot; width=&quot;130&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;175&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;sshd (3201)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;90&quot; y1=&quot;115&quot; x2=&quot;80&quot; y2=&quot;155&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Level 3 from gdm --&gt;
  &lt;rect x=&quot;170&quot; y=&quot;155&quot; width=&quot;140&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;240&quot; y=&quot;175&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;gnome-shell (830)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;115&quot; x2=&quot;240&quot; y2=&quot;155&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Level 4 from sshd child --&gt;
  &lt;rect x=&quot;15&quot; y=&quot;220&quot; width=&quot;130&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;240&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;bash (3202)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;80&quot; y1=&quot;185&quot; x2=&quot;80&quot; y2=&quot;220&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Level 4 from gnome-shell --&gt;
  &lt;rect x=&quot;170&quot; y=&quot;220&quot; width=&quot;140&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;240&quot; y=&quot;240&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;gnome-terminal (1400)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;185&quot; x2=&quot;240&quot; y2=&quot;220&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Level 5 --&gt;
  &lt;rect x=&quot;15&quot; y=&quot;270&quot; width=&quot;130&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;287&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;vim (3250)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;80&quot; y1=&quot;250&quot; x2=&quot;80&quot; y2=&quot;270&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;170&quot; y=&quot;270&quot; width=&quot;140&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;240&quot; y=&quot;287&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;bash (1401)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;250&quot; x2=&quot;240&quot; y2=&quot;270&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- nginx workers --&gt;
  &lt;rect x=&quot;460&quot; y=&quot;155&quot; width=&quot;110&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;515&quot; y=&quot;175&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;worker (521)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;515&quot; y1=&quot;115&quot; x2=&quot;515&quot; y2=&quot;155&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;460&quot; y=&quot;195&quot; width=&quot;110&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;515&quot; y=&quot;215&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;worker (522)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;515&quot; y1=&quot;185&quot; x2=&quot;515&quot; y2=&quot;195&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Every process has a parent, forming a tree rooted at PID 1. Your shell, your editor, and every command you run are branches on this tree.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;signals&quot;&gt;Signals&lt;&#x2F;h2&gt;
&lt;p&gt;Processes communicate with each other and with the kernel through &lt;strong&gt;signals&lt;&#x2F;strong&gt; -- small, numbered notifications. When a process receives a signal, it can handle it (run a custom function), ignore it, or accept the default behavior (which is usually to terminate).&lt;&#x2F;p&gt;
&lt;p&gt;The most commonly encountered signals:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Signal&lt;&#x2F;th&gt;&lt;th&gt;Number&lt;&#x2F;th&gt;&lt;th&gt;Default&lt;&#x2F;th&gt;&lt;th&gt;Typical Source&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;SIGTERM&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;Terminate&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;kill&lt;&#x2F;code&gt; command&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SIGKILL&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;Terminate (cannot be caught)&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;kill -9&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SIGINT&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;Terminate&lt;&#x2F;td&gt;&lt;td&gt;Ctrl+C&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SIGTSTP&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;Stop&lt;&#x2F;td&gt;&lt;td&gt;Ctrl+Z&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SIGCONT&lt;&#x2F;td&gt;&lt;td&gt;18&lt;&#x2F;td&gt;&lt;td&gt;Continue&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;fg&lt;&#x2F;code&gt; or &lt;code&gt;bg&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SIGHUP&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;Terminate&lt;&#x2F;td&gt;&lt;td&gt;Terminal closed&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SIGCHLD&lt;&#x2F;td&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;td&gt;Ignore&lt;&#x2F;td&gt;&lt;td&gt;Child process exited&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SIGSEGV&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;Terminate + core dump&lt;&#x2F;td&gt;&lt;td&gt;Invalid memory access&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Two signals cannot be caught or ignored: SIGKILL (9) and SIGSTOP (19). These are the kernel&#x27;s guarantee that any process (except PID 1) can always be stopped or killed.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Signals are the Unix mechanism for process-to-process and kernel-to-process notification. SIGKILL and SIGSTOP cannot be caught or ignored. Every other signal can be handled by the receiving process.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;seeing-it-in-action&quot;&gt;Seeing It in Action&lt;&#x2F;h2&gt;
&lt;p&gt;You can observe the process model with a few commands:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;# Show the process tree
pstree -p

# Show all processes with details
ps aux

# Watch processes in real time
top

# Trace the system calls a process makes (including fork and exec)
strace -f -e trace=process bash -c &amp;quot;ls&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;strace&lt;&#x2F;code&gt; example is particularly illuminating. You will see your shell call &lt;code&gt;clone()&lt;&#x2F;code&gt; (Linux&#x27;s version of &lt;code&gt;fork()&lt;&#x2F;code&gt;), then the child call &lt;code&gt;execve(&quot;&#x2F;usr&#x2F;bin&#x2F;ls&quot;, ...)&lt;&#x2F;code&gt;. The parent calls &lt;code&gt;wait4()&lt;&#x2F;code&gt; to collect the result. This is the fork-exec-wait pattern playing out in real time, exactly as described.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-this-matters&quot;&gt;Why This Matters&lt;&#x2F;h2&gt;
&lt;p&gt;Every time you type a command at a shell prompt, the shell forks a child, the child execs the command, and the shell waits for it to finish. Every time a web server handles a request (in the traditional model), it forks a worker. Every time you start a program from a GUI menu, a process calls fork() and exec().&lt;&#x2F;p&gt;
&lt;p&gt;The process model is the foundation on which everything else in the operating system rests. Pipes, redirections, job control, services, containers -- they all build on these three system calls. Understanding fork(), exec(), and wait() is understanding how Unix works.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;16-the-tty-and-terminal&#x2F;&quot;&gt;The TTY and Terminal&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>PID 1: init and systemd</title>
        <published>2025-01-18T00:00:00+00:00</published>
        <updated>2025-01-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/14-pid-1-init-and-systemd/"/>
        <id>https://t34ch.tech/coldboot/articles/14-pid-1-init-and-systemd/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/14-pid-1-init-and-systemd/">&lt;p&gt;In the previous articles, the kernel initialized hardware, loaded drivers, and mounted the root filesystem. The kernel itself is not a program you interact with. It is the platform on which programs run. Now it needs to hand control to a program that will build the rest of the system -- start services, mount additional filesystems, configure networking, and eventually present you with a login prompt.&lt;&#x2F;p&gt;
&lt;p&gt;That program is process number one. Every other process on the system descends from it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-handoff&quot;&gt;The Handoff&lt;&#x2F;h2&gt;
&lt;p&gt;At the very end of kernel initialization, the kernel calls a function named &lt;code&gt;kernel_init&lt;&#x2F;code&gt;. This function does one thing: it looks for an executable to run as the first userspace process. The kernel searches a short list of paths in order:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Whatever was passed as &lt;code&gt;init=&lt;&#x2F;code&gt; on the kernel command line&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;sbin&#x2F;init&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;etc&#x2F;init&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;bin&#x2F;init&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;bin&#x2F;sh&lt;&#x2F;code&gt; (last resort)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;When it finds one, the kernel creates a new process, assigns it &lt;strong&gt;PID 1&lt;&#x2F;strong&gt; (process identifier 1), and executes the program. From this moment forward, the kernel&#x27;s job is to provide system calls and manage hardware. PID 1 is responsible for everything else.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: PID&lt;&#x2F;strong&gt;
A process identifier. The kernel assigns a unique integer to every running process. PID 1 is always the init process -- the first userspace program started by the kernel.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 14a -- The kernel to userspace handoff&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Kernel box --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;20&quot; width=&quot;200&quot; height=&quot;60&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;45&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;KERNEL&lt;&#x2F;text&gt;
  &lt;text x=&quot;140&quot; y=&quot;62&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;kernel_init()&lt;&#x2F;text&gt;
  &lt;!-- Arrow down --&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;80&quot; x2=&quot;140&quot; y2=&quot;120&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;133,115 140,128 147,115&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;!-- Search list --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;130&quot; width=&quot;200&quot; height=&quot;110&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;150&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Search order:&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;170&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;1. init= parameter&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;186&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;2. &#x2F;sbin&#x2F;init&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;202&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;3. &#x2F;etc&#x2F;init&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;218&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;4. &#x2F;bin&#x2F;init&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;234&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;5. &#x2F;bin&#x2F;sh (fallback)&lt;&#x2F;text&gt;
  &lt;!-- PID 1 box --&gt;
  &lt;rect x=&quot;320&quot; y=&quot;130&quot; width=&quot;220&quot; height=&quot;110&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;155&quot; fill=&quot;#39D353&quot; font-size=&quot;14&quot; text-anchor=&quot;middle&quot;&gt;PID 1&lt;&#x2F;text&gt;
  &lt;text x=&quot;430&quot; y=&quot;175&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;sbin&#x2F;init&lt;&#x2F;text&gt;
  &lt;text x=&quot;430&quot; y=&quot;200&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Starts all services&lt;&#x2F;text&gt;
  &lt;text x=&quot;430&quot; y=&quot;216&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Mounts filesystems&lt;&#x2F;text&gt;
  &lt;text x=&quot;430&quot; y=&quot;232&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Adopts orphan processes&lt;&#x2F;text&gt;
  &lt;!-- Arrow from search to PID 1 --&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;185&quot; x2=&quot;315&quot; y2=&quot;185&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;310,179 323,185 310,191&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;!-- Label --&gt;
&lt;p&gt;&lt;text x=&quot;277&quot; y=&quot;175&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;exec()&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Divider label --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;265&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;kernel space | userspace&lt;&#x2F;text&gt;
&lt;line x1=&quot;40&quot; y1=&quot;255&quot; x2=&quot;540&quot; y2=&quot;255&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The kernel searches for an init binary, then executes it as PID 1. This is the boundary between kernel initialization and userspace.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;why-pid-1-is-special&quot;&gt;Why PID 1 Is Special&lt;&#x2F;h2&gt;
&lt;p&gt;PID 1 is not just the first process. The kernel treats it differently from every other process on the system.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;It cannot be killed.&lt;&#x2F;strong&gt; The kernel will not deliver fatal signals to PID 1 unless PID 1 has explicitly registered a handler for that signal. If you run &lt;code&gt;kill -9 1&lt;&#x2F;code&gt; as root, nothing happens. On any other process, signal 9 (SIGKILL) is instant, unavoidable death. PID 1 is immune. If PID 1 dies, the kernel panics and the system halts.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;It adopts orphans.&lt;&#x2F;strong&gt; When a process dies, its children need a parent. The kernel reassigns orphaned children to PID 1. This prevents the process table from filling with unmanaged entries.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;It reaps zombies.&lt;&#x2F;strong&gt; When a child process exits, it lingers as a zombie until its parent reads the exit status. PID 1 must periodically call &lt;code&gt;wait()&lt;&#x2F;code&gt; to collect these dead children. If it does not, zombie processes accumulate.&lt;&#x2F;p&gt;
&lt;p&gt;These responsibilities make PID 1 the most critical userspace program on the system. Everything else can crash and be restarted. PID 1 must keep running from the moment it starts until the system shuts down.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
PID 1 has three unique responsibilities: it bootstraps all other services, it adopts orphaned child processes, and it reaps zombie processes. If PID 1 dies, the kernel panics.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;a-brief-history-of-init&quot;&gt;A Brief History of Init&lt;&#x2F;h2&gt;
&lt;p&gt;The concept of a first process dates back to the earliest Unix systems in the 1970s. Over the decades, several implementations have competed for the role.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sysv-init&quot;&gt;SysV Init&lt;&#x2F;h3&gt;
&lt;p&gt;The original System V init, dating to the early 1980s, is the simplest design. It reads a file called &lt;code&gt;&#x2F;etc&#x2F;inittab&lt;&#x2F;code&gt; that defines &lt;strong&gt;runlevels&lt;&#x2F;strong&gt; -- numbered operating modes for the system.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Runlevel&lt;&#x2F;th&gt;&lt;th&gt;Purpose&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;Halt (shut down)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;Single-user mode (maintenance)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;Multi-user, no networking&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;Multi-user with networking&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;Multi-user with networking and GUI&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;Reboot&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;SysV init starts services by running shell scripts sequentially. The scripts live in directories like &lt;code&gt;&#x2F;etc&#x2F;rc3.d&#x2F;&lt;&#x2F;code&gt; (for runlevel 3). Each script is named with a prefix like &lt;code&gt;S01&lt;&#x2F;code&gt; or &lt;code&gt;K99&lt;&#x2F;code&gt; -- the letter indicates start or kill, and the number sets the order.&lt;&#x2F;p&gt;
&lt;p&gt;This design is simple to understand but slow. Services start one at a time, in a fixed order, even when they have no dependency on each other. On modern hardware with dozens of services, booting with SysV init takes noticeably longer than it should.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Runlevel&lt;&#x2F;strong&gt;
A numbered operating mode in SysV init. Each runlevel defines which services should be running. Switching runlevels starts and stops services to match the target configuration.
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;upstart&quot;&gt;Upstart&lt;&#x2F;h3&gt;
&lt;p&gt;Ubuntu introduced Upstart in 2006 as an event-driven replacement for SysV init. Instead of fixed runlevels and sequential scripts, Upstart could react to events -- &quot;when the network is up, start the web server.&quot; This was a significant improvement, but Upstart&#x27;s event model was complex and its adoption remained limited to Ubuntu and a few other distributions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;systemd&quot;&gt;systemd&lt;&#x2F;h3&gt;
&lt;p&gt;In 2010, Lennart Poettering and Kay Sievers created systemd. By 2015, virtually every major Linux distribution had adopted it. systemd is what you are almost certainly running today.&lt;&#x2F;p&gt;
&lt;p&gt;systemd replaced more than just the init process. It absorbed functionality that was previously scattered across dozens of separate tools: service management, logging, device management, login tracking, time synchronization, DNS resolution, and more. This consolidation is both its greatest strength and its most frequent criticism.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-systemd-works&quot;&gt;How systemd Works&lt;&#x2F;h2&gt;
&lt;p&gt;systemd organizes the system around &lt;strong&gt;units&lt;&#x2F;strong&gt;. A unit is a configuration file that describes a resource the system manages. There are several types:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Unit Type&lt;&#x2F;th&gt;&lt;th&gt;File Extension&lt;&#x2F;th&gt;&lt;th&gt;Purpose&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Service&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.service&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;A daemon or one-shot program&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Target&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.target&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;A group of units (replaces runlevels)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Mount&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.mount&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;A filesystem mount point&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Socket&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.socket&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;A network or IPC socket&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Timer&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.timer&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;A scheduled task (replaces cron)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Device&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.device&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;A kernel device&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Unit files live in &lt;code&gt;&#x2F;usr&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;&lt;&#x2F;code&gt; (distribution defaults) and &lt;code&gt;&#x2F;etc&#x2F;systemd&#x2F;system&#x2F;&lt;&#x2F;code&gt; (administrator overrides). When both exist for the same unit, the &lt;code&gt;&#x2F;etc&lt;&#x2F;code&gt; version wins.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 14b -- systemd unit dependency tree&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- default.target --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;15&quot; width=&quot;160&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;38&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;default.target&lt;&#x2F;text&gt;
  &lt;!-- multi-user.target --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;80&quot; width=&quot;160&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;103&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;multi-user.target&lt;&#x2F;text&gt;
  &lt;!-- Arrow default -&gt; multi-user --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;51&quot; x2=&quot;290&quot; y2=&quot;80&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;284,75 290,83 296,75&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;!-- Services row --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;150&quot; width=&quot;130&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;85&quot; y=&quot;173&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;sshd.service&lt;&#x2F;text&gt;
  &lt;rect x=&quot;165&quot; y=&quot;150&quot; width=&quot;130&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;230&quot; y=&quot;173&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;nginx.service&lt;&#x2F;text&gt;
  &lt;rect x=&quot;310&quot; y=&quot;150&quot; width=&quot;130&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;375&quot; y=&quot;173&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;NetworkManager&lt;&#x2F;text&gt;
  &lt;rect x=&quot;455&quot; y=&quot;150&quot; width=&quot;105&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;507&quot; y=&quot;173&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;cron.service&lt;&#x2F;text&gt;
  &lt;!-- Arrows from multi-user to services --&gt;
  &lt;line x1=&quot;250&quot; y1=&quot;116&quot; x2=&quot;85&quot; y2=&quot;150&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;270&quot; y1=&quot;116&quot; x2=&quot;230&quot; y2=&quot;150&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;310&quot; y1=&quot;116&quot; x2=&quot;375&quot; y2=&quot;150&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;330&quot; y1=&quot;116&quot; x2=&quot;507&quot; y2=&quot;150&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Dependency row --&gt;
  &lt;rect x=&quot;100&quot; y=&quot;225&quot; width=&quot;160&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;180&quot; y=&quot;248&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;network-online.target&lt;&#x2F;text&gt;
  &lt;rect x=&quot;320&quot; y=&quot;225&quot; width=&quot;160&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;400&quot; y=&quot;248&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;basic.target&lt;&#x2F;text&gt;
  &lt;!-- Arrows from services to deps --&gt;
  &lt;line x1=&quot;85&quot; y1=&quot;186&quot; x2=&quot;180&quot; y2=&quot;225&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;230&quot; y1=&quot;186&quot; x2=&quot;180&quot; y2=&quot;225&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;375&quot; y1=&quot;186&quot; x2=&quot;400&quot; y2=&quot;225&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;507&quot; y1=&quot;186&quot; x2=&quot;400&quot; y2=&quot;225&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;!-- sysinit.target --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;295&quot; width=&quot;160&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;318&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;sysinit.target&lt;&#x2F;text&gt;
  &lt;!-- Arrow --&gt;
  &lt;line x1=&quot;400&quot; y1=&quot;261&quot; x2=&quot;330&quot; y2=&quot;295&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;180&quot; y1=&quot;261&quot; x2=&quot;250&quot; y2=&quot;295&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;!-- Legend --&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;318&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;--- requires&#x2F;depends on&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;systemd resolves a tree of dependencies. Targets group related services. Services declare what they need, and systemd starts them in parallel where possible.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h3 id=&quot;targets-replace-runlevels&quot;&gt;Targets Replace Runlevels&lt;&#x2F;h3&gt;
&lt;p&gt;systemd does not use runlevels. Instead, it uses &lt;strong&gt;targets&lt;&#x2F;strong&gt; -- units that group other units together. The mapping is roughly:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;SysV Runlevel&lt;&#x2F;th&gt;&lt;th&gt;systemd Target&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;poweroff.target&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;rescue.target&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;multi-user.target&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;graphical.target&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;reboot.target&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The default target is usually &lt;code&gt;graphical.target&lt;&#x2F;code&gt; on desktop systems and &lt;code&gt;multi-user.target&lt;&#x2F;code&gt; on servers. You can check your system&#x27;s default with:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;systemctl get-default
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;parallel-startup&quot;&gt;Parallel Startup&lt;&#x2F;h3&gt;
&lt;p&gt;The most visible improvement systemd brings is parallelism. SysV init starts services one at a time. systemd reads all the unit files, builds a dependency graph, and starts everything it can simultaneously.&lt;&#x2F;p&gt;
&lt;p&gt;If service A and service B have no dependency on each other, they start at the same time. If service C depends on A, it waits only for A and starts as soon as A reports ready. This can cut boot times in half or better.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-service-unit-file&quot;&gt;A Service Unit File&lt;&#x2F;h3&gt;
&lt;p&gt;Here is a typical service unit file:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;ini&quot;&gt;[Unit]
Description=OpenSSH Daemon
After=network.target

[Service]
Type=notify
ExecStart=&#x2F;usr&#x2F;sbin&#x2F;sshd -D
ExecReload=&#x2F;bin&#x2F;kill -HUP $MAINPID
Restart=on-failure

[Install]
WantedBy=multi-user.target
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;[Unit]&lt;&#x2F;code&gt; section declares ordering -- this service should start after the network is available. The &lt;code&gt;[Service]&lt;&#x2F;code&gt; section defines how to run the program. &lt;code&gt;Type=notify&lt;&#x2F;code&gt; means the service will explicitly tell systemd when it is ready. &lt;code&gt;Restart=on-failure&lt;&#x2F;code&gt; means systemd will restart it if it crashes. The &lt;code&gt;[Install]&lt;&#x2F;code&gt; section says that when this service is enabled, it becomes part of &lt;code&gt;multi-user.target&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;managing-services-with-systemctl&quot;&gt;Managing Services with systemctl&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;systemctl&lt;&#x2F;code&gt; is the command you use to interact with systemd. The essential operations:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;systemctl start sshd        # Start a service now
systemctl stop sshd         # Stop a service now
systemctl restart sshd      # Stop, then start
systemctl status sshd       # Show current state
systemctl enable sshd       # Start at boot
systemctl disable sshd      # Do not start at boot
systemctl is-active sshd    # Check if running
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;enable&lt;&#x2F;code&gt; and &lt;code&gt;disable&lt;&#x2F;code&gt; control what happens at boot. &lt;code&gt;start&lt;&#x2F;code&gt; and &lt;code&gt;stop&lt;&#x2F;code&gt; control what is happening right now. They are independent -- you can start a service without enabling it, or enable it without starting it immediately.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 14c -- Service lifecycle in systemd&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 220&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;220&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- States --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;70&quot; y=&quot;105&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;inactive&lt;&#x2F;text&gt;
  &lt;rect x=&quot;160&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;210&quot; y=&quot;105&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;activating&lt;&#x2F;text&gt;
  &lt;rect x=&quot;300&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;350&quot; y=&quot;105&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;active&lt;&#x2F;text&gt;
  &lt;rect x=&quot;455&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;505&quot; y=&quot;105&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;failed&lt;&#x2F;text&gt;
  &lt;!-- Arrows --&gt;
  &lt;line x1=&quot;120&quot; y1=&quot;100&quot; x2=&quot;155&quot; y2=&quot;100&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;152,94 162,100 152,106&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
  &lt;text x=&quot;138&quot; y=&quot;88&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;start&lt;&#x2F;text&gt;
  &lt;line x1=&quot;260&quot; y1=&quot;100&quot; x2=&quot;295&quot; y2=&quot;100&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;292,94 302,100 292,106&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
  &lt;text x=&quot;278&quot; y=&quot;88&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;ready&lt;&#x2F;text&gt;
  &lt;line x1=&quot;400&quot; y1=&quot;100&quot; x2=&quot;450&quot; y2=&quot;100&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;447,94 457,100 447,106&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;425&quot; y=&quot;88&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;crash&lt;&#x2F;text&gt;
  &lt;!-- Restart loop --&gt;
  &lt;path d=&quot;M 505 120 L 505 170 L 210 170 L 210 125&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;polygon points=&quot;204,128 210,118 216,128&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
  &lt;text x=&quot;360&quot; y=&quot;165&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Restart=on-failure&lt;&#x2F;text&gt;
  &lt;!-- Stop arrow back --&gt;
  &lt;path d=&quot;M 350 80 L 350 40 L 70 40 L 70 75&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;64,72 70,82 76,72&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;text x=&quot;210&quot; y=&quot;35&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;stop&lt;&#x2F;text&gt;
  &lt;!-- Legend --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;210&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;systemd automatically restarts failed services when configured&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A service moves through states. systemd can automatically restart failed services, creating a self-healing loop.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-boot-sequence-under-systemd&quot;&gt;The Boot Sequence Under systemd&lt;&#x2F;h2&gt;
&lt;p&gt;When the kernel starts systemd as PID 1, the boot proceeds through a predictable chain of targets:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;sysinit.target&lt;&#x2F;strong&gt; -- mount essential filesystems, load kernel modules, activate swap, seed the random number generator.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;basic.target&lt;&#x2F;strong&gt; -- start logging, timers, and socket activation.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;multi-user.target&lt;&#x2F;strong&gt; -- start all non-graphical services: networking, SSH, databases, web servers.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;graphical.target&lt;&#x2F;strong&gt; (if configured) -- start the display manager and desktop environment.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Each target pulls in the targets before it through dependency chains. systemd resolves the entire graph at once and starts everything it can in parallel, only serializing where an explicit ordering exists.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
systemd replaced sequential shell scripts with a dependency graph. Services declare what they need, and systemd starts everything in parallel where possible. This is why modern Linux boots fast.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-journal&quot;&gt;The Journal&lt;&#x2F;h2&gt;
&lt;p&gt;systemd includes its own logging system called the &lt;strong&gt;journal&lt;&#x2F;strong&gt;, managed by &lt;code&gt;journald&lt;&#x2F;code&gt;. Instead of plain text files in &lt;code&gt;&#x2F;var&#x2F;log&#x2F;&lt;&#x2F;code&gt;, the journal stores structured, indexed, binary log entries.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u sshd          # Logs from sshd
journalctl -b                # Logs from current boot
journalctl --since &amp;quot;1 hour ago&amp;quot;
journalctl -f                # Follow new entries (like tail -f)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The journal captures both stdout and stderr from every service. This means you do not need to configure logging in each service individually -- systemd captures it all.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;controversy-and-alternatives&quot;&gt;Controversy and Alternatives&lt;&#x2F;h2&gt;
&lt;p&gt;systemd&#x27;s expansion beyond a simple init replacement has drawn criticism. Some argue it violates the Unix philosophy of small, focused tools. Others worry about the complexity of depending on a single project for so many system functions.&lt;&#x2F;p&gt;
&lt;p&gt;Alternatives exist. &lt;strong&gt;OpenRC&lt;&#x2F;strong&gt; is used by Gentoo and Alpine Linux. &lt;strong&gt;runit&lt;&#x2F;strong&gt; is used by Void Linux. &lt;strong&gt;s6&lt;&#x2F;strong&gt; is a supervision suite popular in container images. Each takes a more minimal approach, managing services without absorbing logging, networking, and device management.&lt;&#x2F;p&gt;
&lt;p&gt;For learning purposes, understanding systemd is essential -- it runs on the vast majority of Linux installations. But it is worth knowing that PID 1 does not have to be this complex. The kernel only requires that something runs as PID 1, reaps zombies, and adopts orphans. Everything else is a design choice.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-pid-1-means-for-you&quot;&gt;What PID 1 Means for You&lt;&#x2F;h2&gt;
&lt;p&gt;When you sit down at a Linux system and see a login prompt, that prompt exists because PID 1 started a chain of services that made it possible. The network works because PID 1 started NetworkManager. Your SSH sessions work because PID 1 started sshd. Your disk is mounted because PID 1 triggered the mount units.&lt;&#x2F;p&gt;
&lt;p&gt;If a service is not running, &lt;code&gt;systemctl status&lt;&#x2F;code&gt; will tell you why. If the system will not boot, understanding the target chain tells you where to look. PID 1 is the root of the entire userspace tree, and every other process on the system exists because, directly or indirectly, PID 1 started it.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;15-the-process-model&#x2F;&quot;&gt;The Process Model&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Root Filesystem</title>
        <published>2025-01-17T00:00:00+00:00</published>
        <updated>2025-01-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/13-the-root-filesystem/"/>
        <id>https://t34ch.tech/coldboot/articles/13-the-root-filesystem/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/13-the-root-filesystem/">&lt;p&gt;The kernel has initialized its subsystems, loaded its built-in drivers, and set up memory management and scheduling. But it still cannot do most of what an operating system needs to do. It cannot run programs from disk. It cannot read configuration files. It cannot load additional driver modules. All of these require a filesystem -- a structured way to organize, name, and access files stored on a device.&lt;&#x2F;p&gt;
&lt;p&gt;The first filesystem the kernel mounts is called the root filesystem. It is mounted at &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; -- the single forward slash that is the top of the entire directory tree. Every file path on a Linux system starts from this point. Before the root filesystem exists, the system has no &lt;code&gt;&#x2F;bin&lt;&#x2F;code&gt;, no &lt;code&gt;&#x2F;etc&lt;&#x2F;code&gt;, no &lt;code&gt;&#x2F;home&lt;&#x2F;code&gt;. It has nothing.&lt;&#x2F;p&gt;
&lt;p&gt;This article explains how the kernel gets from &quot;no filesystem at all&quot; to a fully mounted root, and the intermediate step that makes it possible.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-chicken-and-egg-problem&quot;&gt;The Chicken-and-Egg Problem&lt;&#x2F;h2&gt;
&lt;p&gt;To mount the root filesystem, the kernel needs a storage driver -- the software that knows how to talk to the disk. But many storage drivers are compiled as loadable modules, stored as files on the root filesystem. You need the driver to read the disk. You need the disk to load the driver.&lt;&#x2F;p&gt;
&lt;p&gt;This circular dependency is one of the classic problems of operating system design. Linux solves it with a temporary filesystem that the bootloader loads into RAM alongside the kernel itself. This temporary filesystem is called the initramfs.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: initramfs (initial RAM filesystem)&lt;&#x2F;strong&gt;
A small, compressed filesystem archive that the bootloader loads into memory alongside the kernel. It contains the essential drivers, tools, and scripts needed to find and mount the real root filesystem. Once the real root is mounted, the initramfs is discarded.
&lt;&#x2F;div&gt;
&lt;p&gt;Think of it like a toolbox you carry with you to a construction site. The site has all the heavy equipment, but the gate is locked. Your toolbox has the key. Once you open the gate and get the heavy equipment running, you do not need the toolbox anymore.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-inside-the-initramfs&quot;&gt;What is Inside the initramfs&lt;&#x2F;h2&gt;
&lt;p&gt;The initramfs is a compressed cpio archive -- a simple format that packs files and directories into a single stream. When the kernel starts, it unpacks this archive into a temporary in-memory filesystem (a tmpfs) and uses it as the initial root.&lt;&#x2F;p&gt;
&lt;p&gt;A typical initramfs contains:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kernel modules&lt;&#x2F;strong&gt; for the storage controller (NVMe, AHCI, SCSI, USB storage)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Filesystem modules&lt;&#x2F;strong&gt; (ext4, XFS, Btrfs) so the kernel can understand the root partition&#x27;s format&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A small init script or binary&lt;&#x2F;strong&gt; that orchestrates the mounting process&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Essential tools&lt;&#x2F;strong&gt; like &lt;code&gt;busybox&lt;&#x2F;code&gt; (a single binary that provides dozens of standard Unix utilities)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Device manager&lt;&#x2F;strong&gt; components (a minimal udev or mdev) to create &#x2F;dev entries for detected hardware&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Cryptographic modules&lt;&#x2F;strong&gt; if the root partition is encrypted (LUKS&#x2F;dm-crypt)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can examine your system&#x27;s initramfs:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ lsinitramfs &#x2F;boot&#x2F;initrd.img-6.8.0-generic | head -10
.
bin
bin&#x2F;busybox
bin&#x2F;cat
bin&#x2F;cp
conf
conf&#x2F;initramfs.conf
etc
etc&#x2F;modprobe.d
lib
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The entire image is typically 20-60 MB compressed, expanding to perhaps 100-200 MB when unpacked. This is tiny compared to a full root filesystem, which may be tens of gigabytes. The initramfs carries only what is needed to get to the real root.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 13a -- initramfs boot sequence&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 360&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;360&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- RAM representation --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;20&quot; width=&quot;540&quot; height=&quot;320&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;15&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;RAM&lt;&#x2F;text&gt;
  &lt;!-- Step 1 --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;35&quot; width=&quot;230&quot; height=&quot;55&quot; rx=&quot;4&quot; fill=&quot;#35383C&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;55&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;1. Bootloader loads:&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;75&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot;&gt;kernel + initramfs&lt;&#x2F;text&gt;
  &lt;!-- Step 2 --&gt;
  &lt;rect x=&quot;300&quot; y=&quot;35&quot; width=&quot;240&quot; height=&quot;55&quot; rx=&quot;4&quot; fill=&quot;#35383C&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;55&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;2. Kernel unpacks initramfs&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;75&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;cpio archive -&gt; tmpfs at &#x2F;&lt;&#x2F;text&gt;
  &lt;!-- Arrow --&gt;
  &lt;line x1=&quot;270&quot; y1=&quot;62&quot; x2=&quot;300&quot; y2=&quot;62&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13)&quot;&#x2F;&gt;
  &lt;!-- Initramfs contents --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;105&quot; width=&quot;500&quot; height=&quot;90&quot; rx=&quot;4&quot; fill=&quot;#35383C&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;125&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;3. initramfs filesystem (tmpfs at &#x2F;)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;55&quot; y=&quot;135&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;155&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;init script&lt;&#x2F;text&gt;
  &lt;rect x=&quot;155&quot; y=&quot;135&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;200&quot; y=&quot;155&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;bin&#x2F;busybox&lt;&#x2F;text&gt;
  &lt;rect x=&quot;255&quot; y=&quot;135&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;305&quot; y=&quot;155&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;lib&#x2F;modules&#x2F;&lt;&#x2F;text&gt;
  &lt;rect x=&quot;365&quot; y=&quot;135&quot; width=&quot;80&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;405&quot; y=&quot;155&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;etc&#x2F;conf&lt;&#x2F;text&gt;
  &lt;rect x=&quot;455&quot; y=&quot;135&quot; width=&quot;70&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;490&quot; y=&quot;155&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;dev&lt;&#x2F;text&gt;
  &lt;!-- Arrow down --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;195&quot; x2=&quot;290&quot; y2=&quot;215&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13)&quot;&#x2F;&gt;
  &lt;!-- Step 4: init script runs --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;215&quot; width=&quot;240&quot; height=&quot;55&quot; rx=&quot;4&quot; fill=&quot;#35383C&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;235&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;4. &#x2F;init loads drivers&lt;&#x2F;text&gt;
  &lt;text x=&quot;160&quot; y=&quot;255&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;modprobe nvme, ext4, ...&lt;&#x2F;text&gt;
  &lt;!-- Arrow right --&gt;
  &lt;line x1=&quot;280&quot; y1=&quot;242&quot; x2=&quot;310&quot; y2=&quot;242&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13)&quot;&#x2F;&gt;
  &lt;!-- Step 5: mount real root --&gt;
  &lt;rect x=&quot;310&quot; y=&quot;215&quot; width=&quot;230&quot; height=&quot;55&quot; rx=&quot;4&quot; fill=&quot;#35383C&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;425&quot; y=&quot;235&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;5. Mount real root&lt;&#x2F;text&gt;
  &lt;text x=&quot;425&quot; y=&quot;255&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;mount &#x2F;dev&#x2F;sda2 &#x2F;root&lt;&#x2F;text&gt;
  &lt;!-- Step 6: switch_root --&gt;
  &lt;rect x=&quot;140&quot; y=&quot;290&quot; width=&quot;300&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#35383C&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;315&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;6. switch_root -&gt; real &#x2F; takes over&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;270&quot; x2=&quot;290&quot; y2=&quot;290&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13)&quot;&#x2F;&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr13&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;polygon points=&quot;0,0 8,3 0,6&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The bootloader places both the kernel and the initramfs in RAM. The kernel unpacks the archive into a tmpfs, runs the &#x2F;init script inside it, loads drivers, finds the real root device, mounts it, then switches root.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-init-script&quot;&gt;The &#x2F;init Script&lt;&#x2F;h2&gt;
&lt;p&gt;When the kernel finishes its own initialization, it looks for a program to execute as PID 1 -- the first userspace process. If an initramfs is present, the kernel runs &lt;code&gt;&#x2F;init&lt;&#x2F;code&gt; from within it. This is typically a shell script (on Debian&#x2F;Ubuntu systems using initramfs-tools) or a compiled binary (on systems using dracut).&lt;&#x2F;p&gt;
&lt;p&gt;The init script performs a precise sequence:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Mount the &lt;code&gt;&#x2F;proc&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;sys&lt;&#x2F;code&gt; pseudo-filesystems so it can communicate with the kernel.&lt;&#x2F;li&gt;
&lt;li&gt;Start a minimal device manager (udev or mdev) to create &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt; entries for detected hardware.&lt;&#x2F;li&gt;
&lt;li&gt;Load the storage driver module for the root device.&lt;&#x2F;li&gt;
&lt;li&gt;Load the filesystem module for the root partition&#x27;s format.&lt;&#x2F;li&gt;
&lt;li&gt;If the root is encrypted, prompt for the passphrase and set up the decryption layer.&lt;&#x2F;li&gt;
&lt;li&gt;If the root is on LVM or RAID, assemble the logical volume or array.&lt;&#x2F;li&gt;
&lt;li&gt;Mount the real root filesystem on a temporary mount point (like &lt;code&gt;&#x2F;root&lt;&#x2F;code&gt; or &lt;code&gt;&#x2F;mnt&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Call &lt;code&gt;switch_root&lt;&#x2F;code&gt; to replace the initramfs with the real root filesystem.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;remember&quot;&gt;
The initramfs &#x2F;init script is a carefully ordered sequence. Each step enables the next. Missing a step -- failing to load the right storage driver, for example -- means the real root cannot be mounted, and the boot halts with the dreaded &quot;unable to mount root fs&quot; panic.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;switch-root-the-handoff&quot;&gt;switch_root: The Handoff&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;switch_root&lt;&#x2F;code&gt; command (or &lt;code&gt;pivot_root&lt;&#x2F;code&gt;, an older mechanism) performs the transition from the initramfs to the real root filesystem. It does three things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Deletes everything in the initramfs to free the memory it was using.&lt;&#x2F;li&gt;
&lt;li&gt;Moves the mount of the real root filesystem from its temporary mount point to &lt;code&gt;&#x2F;&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Executes the real init program (typically &lt;code&gt;&#x2F;sbin&#x2F;init&lt;&#x2F;code&gt; or &lt;code&gt;systemd&lt;&#x2F;code&gt;) from the new root.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;After &lt;code&gt;switch_root&lt;&#x2F;code&gt;, the initramfs is gone. The system&#x27;s &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; is now backed by the real disk partition. The real init program takes over as PID 1 and begins starting system services.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: switch_root&lt;&#x2F;strong&gt;
A command that transitions from the initramfs to the real root filesystem. It frees the initramfs memory, moves the real root mount to &#x2F;, and executes the real init binary. This is a one-way operation -- there is no going back to the initramfs.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-old-way-initrd&quot;&gt;The Old Way: initrd&lt;&#x2F;h2&gt;
&lt;p&gt;Before initramfs, Linux used initrd (initial RAM disk). An initrd was a disk image -- a file containing a complete filesystem, formatted as ext2 or similar, loaded into a RAM-based block device. The kernel would mount this block device as the initial root.&lt;&#x2F;p&gt;
&lt;p&gt;initramfs replaced initrd because it is simpler and more flexible. An initramfs is just a cpio archive extracted into tmpfs. It does not need a block device driver, a filesystem driver, or a fixed size allocation. The kernel simply unpacks the archive into memory. Despite this, many systems still name the file &lt;code&gt;initrd.img&lt;&#x2F;code&gt; for historical reasons, even though the contents are actually an initramfs cpio archive.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;filesystem-types&quot;&gt;Filesystem Types&lt;&#x2F;h2&gt;
&lt;p&gt;The real root filesystem needs to be in a format the kernel understands. Linux supports dozens of filesystem types. The most common ones for root partitions:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ext4&lt;&#x2F;strong&gt; -- The fourth extended filesystem. The default for many distributions. It is mature, well-tested, and handles most workloads well. It uses a traditional block allocation scheme with inodes, block groups, and journals.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;XFS&lt;&#x2F;strong&gt; -- Originally developed by SGI for large files and high throughput. Default on Red Hat Enterprise Linux and Fedora. Excels at parallel I&#x2F;O on multi-core systems.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Btrfs&lt;&#x2F;strong&gt; -- A copy-on-write filesystem with built-in support for snapshots, checksums, compression, and multi-device spanning. Default on openSUSE and Fedora Silverblue. More features than ext4 or XFS, but also more complexity.&lt;&#x2F;p&gt;
&lt;p&gt;Each filesystem type is implemented as a kernel module (or built-in code). The initramfs must include the module for whatever filesystem type the real root partition uses. If you format your root as ext4, the initramfs needs &lt;code&gt;ext4.ko&lt;&#x2F;code&gt;. Format it as Btrfs, and you need &lt;code&gt;btrfs.ko&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 13b -- The Virtual Filesystem Switch (VFS)&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Application layer --&gt;
  &lt;rect x=&quot;140&quot; y=&quot;15&quot; width=&quot;300&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;40&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Application: open(&quot;&#x2F;etc&#x2F;hostname&quot;)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;55&quot; x2=&quot;290&quot; y2=&quot;75&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13b)&quot;&#x2F;&gt;
  &lt;!-- System call boundary --&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;68&quot; x2=&quot;520&quot; y2=&quot;68&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;text x=&quot;35&quot; y=&quot;72&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;syscall&lt;&#x2F;text&gt;
  &lt;!-- VFS layer --&gt;
  &lt;rect x=&quot;90&quot; y=&quot;75&quot; width=&quot;400&quot; height=&quot;50&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;97&quot; fill=&quot;#00BFFF&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;VFS -- Virtual Filesystem Switch&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;114&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Uniform API: open, read, write, close, stat, ...&lt;&#x2F;text&gt;
  &lt;!-- Arrows down to FS types --&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;125&quot; x2=&quot;100&quot; y2=&quot;155&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;125&quot; x2=&quot;240&quot; y2=&quot;155&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;350&quot; y1=&quot;125&quot; x2=&quot;350&quot; y2=&quot;155&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;450&quot; y1=&quot;125&quot; x2=&quot;480&quot; y2=&quot;155&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- FS implementations --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;155&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;180&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;ext4&lt;&#x2F;text&gt;
  &lt;rect x=&quot;180&quot; y=&quot;155&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;180&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;XFS&lt;&#x2F;text&gt;
  &lt;rect x=&quot;300&quot; y=&quot;155&quot; width=&quot;110&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;355&quot; y=&quot;180&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Btrfs&lt;&#x2F;text&gt;
  &lt;rect x=&quot;420&quot; y=&quot;155&quot; width=&quot;120&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;180&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;tmpfs&#x2F;proc&lt;&#x2F;text&gt;
  &lt;!-- Arrows to storage --&gt;
  &lt;line x1=&quot;95&quot; y1=&quot;195&quot; x2=&quot;95&quot; y2=&quot;225&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;235&quot; y1=&quot;195&quot; x2=&quot;235&quot; y2=&quot;225&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;355&quot; y1=&quot;195&quot; x2=&quot;355&quot; y2=&quot;225&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;195&quot; x2=&quot;480&quot; y2=&quot;225&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13b)&quot;&#x2F;&gt;
  &lt;!-- Block layer --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;225&quot; width=&quot;370&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;225&quot; y=&quot;247&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Block layer (I&#x2F;O scheduling, queues)&lt;&#x2F;text&gt;
  &lt;!-- RAM label for tmpfs --&gt;
  &lt;rect x=&quot;430&quot; y=&quot;225&quot; width=&quot;110&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;485&quot; y=&quot;247&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;RAM (no disk)&lt;&#x2F;text&gt;
  &lt;!-- Disk --&gt;
  &lt;line x1=&quot;225&quot; y1=&quot;260&quot; x2=&quot;225&quot; y2=&quot;285&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr13b)&quot;&#x2F;&gt;
  &lt;rect x=&quot;120&quot; y=&quot;285&quot; width=&quot;210&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;225&quot; y=&quot;307&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Physical storage (SSD, HDD)&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr13b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;polygon points=&quot;0,0 8,3 0,6&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The VFS provides a single API for all filesystem types. Applications call open&#x2F;read&#x2F;write without knowing whether the file is on ext4, XFS, Btrfs, or an in-memory filesystem like tmpfs. The VFS dispatches each call to the correct filesystem implementation.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-virtual-filesystem-switch-vfs&quot;&gt;The Virtual Filesystem Switch (VFS)&lt;&#x2F;h2&gt;
&lt;p&gt;Applications do not call ext4 or XFS code directly. They call generic kernel functions like &lt;code&gt;open()&lt;&#x2F;code&gt;, &lt;code&gt;read()&lt;&#x2F;code&gt;, &lt;code&gt;write()&lt;&#x2F;code&gt;, and &lt;code&gt;close()&lt;&#x2F;code&gt;. The layer that translates these generic calls into filesystem-specific operations is the Virtual Filesystem Switch, or VFS.&lt;&#x2F;p&gt;
&lt;p&gt;The VFS is an abstraction layer. It defines a set of standard operations that every filesystem must implement. When you call &lt;code&gt;open(&quot;&#x2F;etc&#x2F;hostname&quot;)&lt;&#x2F;code&gt;, the VFS figures out which filesystem &lt;code&gt;&#x2F;etc&#x2F;hostname&lt;&#x2F;code&gt; lives on, looks up that filesystem&#x27;s implementation of the open operation, and calls it.&lt;&#x2F;p&gt;
&lt;p&gt;This is what makes it possible to mix filesystem types on a single system. Your root might be ext4 at &lt;code&gt;&#x2F;&lt;&#x2F;code&gt;, your home directory might be on a Btrfs partition mounted at &lt;code&gt;&#x2F;home&lt;&#x2F;code&gt;, and &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt; might be a tmpfs in RAM. The VFS stitches them all into one seamless directory tree.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: VFS (Virtual Filesystem Switch)&lt;&#x2F;strong&gt;
The kernel layer that provides a uniform interface for all filesystem types. It defines standard operations (open, read, write, stat, etc.) and dispatches them to the appropriate filesystem implementation based on which mount point the file belongs to. Applications never interact with a specific filesystem directly.
&lt;&#x2F;div&gt;
&lt;p&gt;The VFS maintains several key data structures:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Superblock&lt;&#x2F;strong&gt; -- represents a mounted filesystem. Contains metadata like block size, total size, and available space.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Inode&lt;&#x2F;strong&gt; -- represents a file or directory. Contains permissions, ownership, timestamps, and pointers to data blocks.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Dentry&lt;&#x2F;strong&gt; -- represents a directory entry, mapping a filename to an inode. The kernel caches dentries for fast path lookups.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;File&lt;&#x2F;strong&gt; -- represents an open file, tied to a specific process. Contains the current read&#x2F;write position and the operations table for that file&#x27;s filesystem.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;what-actually-is&quot;&gt;What &quot;&#x2F;&quot; Actually Is&lt;&#x2F;h2&gt;
&lt;p&gt;The root filesystem is not just the first filesystem mounted. It is the anchor for everything else. Every other filesystem mount in the system attaches to a directory within the root filesystem&#x27;s tree.&lt;&#x2F;p&gt;
&lt;p&gt;When you mount a partition at &lt;code&gt;&#x2F;home&lt;&#x2F;code&gt;, you are grafting that partition&#x27;s directory tree onto the &lt;code&gt;&#x2F;home&lt;&#x2F;code&gt; directory of the root filesystem. The original contents of &lt;code&gt;&#x2F;home&lt;&#x2F;code&gt; (if any) on the root filesystem become hidden -- replaced by the contents of the mounted partition. Unmount the partition, and the original contents reappear.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 13c -- Mount points graft filesystems together&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 330&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;330&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Root FS tree --&gt;
  &lt;rect x=&quot;230&quot; y=&quot;15&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;37&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;&#x2F; (ext4)&lt;&#x2F;text&gt;
  &lt;!-- Root children --&gt;
  &lt;line x1=&quot;250&quot; y1=&quot;50&quot; x2=&quot;100&quot; y2=&quot;80&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;270&quot; y1=&quot;50&quot; x2=&quot;220&quot; y2=&quot;80&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;310&quot; y1=&quot;50&quot; x2=&quot;360&quot; y2=&quot;80&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;330&quot; y1=&quot;50&quot; x2=&quot;480&quot; y2=&quot;80&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;100&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;bin&lt;&#x2F;text&gt;
  &lt;rect x=&quot;170&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;220&quot; y=&quot;100&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;etc&lt;&#x2F;text&gt;
  &lt;!-- &#x2F;home mount point --&gt;
  &lt;rect x=&quot;310&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;360&quot; y=&quot;100&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;home&lt;&#x2F;text&gt;
  &lt;!-- &#x2F;tmp mount point --&gt;
  &lt;rect x=&quot;430&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;100&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;tmp&lt;&#x2F;text&gt;
  &lt;!-- Mount indicators --&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;110&quot; x2=&quot;360&quot; y2=&quot;140&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;110&quot; x2=&quot;480&quot; y2=&quot;140&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;!-- Btrfs filesystem --&gt;
  &lt;rect x=&quot;280&quot; y=&quot;140&quot; width=&quot;160&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;360&quot; y=&quot;162&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Btrfs partition&lt;&#x2F;text&gt;
  &lt;line x1=&quot;320&quot; y1=&quot;175&quot; x2=&quot;300&quot; y2=&quot;200&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;400&quot; y1=&quot;175&quot; x2=&quot;420&quot; y2=&quot;200&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;255&quot; y=&quot;200&quot; width=&quot;90&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;217&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;home&#x2F;alice&lt;&#x2F;text&gt;
  &lt;rect x=&quot;375&quot; y=&quot;200&quot; width=&quot;90&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;217&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;home&#x2F;bob&lt;&#x2F;text&gt;
  &lt;!-- tmpfs --&gt;
  &lt;rect x=&quot;430&quot; y=&quot;140&quot; width=&quot;100&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;162&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;tmpfs (RAM)&lt;&#x2F;text&gt;
  &lt;!-- Labels for each device --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;260&quot; width=&quot;150&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;105&quot; y=&quot;277&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;dev&#x2F;nvme0n1p2&lt;&#x2F;text&gt;
  &lt;text x=&quot;105&quot; y=&quot;291&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;root (ext4)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;215&quot; y=&quot;260&quot; width=&quot;150&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;277&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;dev&#x2F;nvme0n1p3&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;291&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;home (btrfs)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;400&quot; y=&quot;260&quot; width=&quot;150&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;475&quot; y=&quot;277&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;no device&lt;&#x2F;text&gt;
  &lt;text x=&quot;475&quot; y=&quot;291&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;tmpfs (memory)&lt;&#x2F;text&gt;
  &lt;!-- Connecting lines to devices --&gt;
  &lt;line x1=&quot;105&quot; y1=&quot;260&quot; x2=&quot;200&quot; y2=&quot;50&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,5&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;260&quot; x2=&quot;360&quot; y2=&quot;175&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,5&quot;&#x2F;&gt;
  &lt;line x1=&quot;475&quot; y1=&quot;260&quot; x2=&quot;480&quot; y2=&quot;175&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,5&quot;&#x2F;&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Three different filesystems -- ext4 on an NVMe partition, Btrfs on another partition, and tmpfs in RAM -- are grafted together into a single directory tree. Users and applications see one seamless hierarchy.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;This is the mount model. The root filesystem at &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; is the trunk of the tree. Everything else is a branch grafted on. The kernel&#x27;s mount table (visible in &lt;code&gt;&#x2F;proc&#x2F;mounts&lt;&#x2F;code&gt;) records every active mount -- which device, which filesystem type, which mount point, and which options.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ cat &#x2F;proc&#x2F;mounts | head -5
&#x2F;dev&#x2F;nvme0n1p2 &#x2F; ext4 rw,relatime 0 0
&#x2F;dev&#x2F;nvme0n1p3 &#x2F;home btrfs rw,relatime,compress=zstd 0 0
tmpfs &#x2F;tmp tmpfs rw,nosuid,nodev 0 0
proc &#x2F;proc proc rw,nosuid,nodev,noexec 0 0
sysfs &#x2F;sys sysfs rw,nosuid,nodev,noexec 0 0
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;remember&quot;&gt;
The root filesystem is not just one filesystem among many. It is the anchor point for the entire directory hierarchy. Every other mount attaches to a directory within it. Without a root filesystem, there is no place to attach anything, no way to find programs or configuration, and no operating system.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;pseudo-filesystems&quot;&gt;Pseudo-Filesystems&lt;&#x2F;h2&gt;
&lt;p&gt;Not everything mounted in the directory tree represents data on a disk. Linux uses pseudo-filesystems -- filesystems that exist only in memory and provide interfaces to kernel data structures.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;proc&lt;&#x2F;strong&gt; (mounted at &lt;code&gt;&#x2F;proc&lt;&#x2F;code&gt;) -- Provides information about running processes and kernel state. &lt;code&gt;&#x2F;proc&#x2F;cpuinfo&lt;&#x2F;code&gt; shows CPU details. &lt;code&gt;&#x2F;proc&#x2F;meminfo&lt;&#x2F;code&gt; shows memory usage. Each running process has a directory under &lt;code&gt;&#x2F;proc&#x2F;&amp;lt;pid&amp;gt;&#x2F;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;sysfs&lt;&#x2F;strong&gt; (mounted at &lt;code&gt;&#x2F;sys&lt;&#x2F;code&gt;) -- Exposes the kernel&#x27;s device model as a directory hierarchy. Every device, driver, and bus has a directory with attribute files you can read or write.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;tmpfs&lt;&#x2F;strong&gt; (often mounted at &lt;code&gt;&#x2F;tmp&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;run&lt;&#x2F;code&gt;) -- A filesystem that lives entirely in RAM. Files written to tmpfs are fast to access but disappear on reboot. The initramfs itself is a tmpfs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;devtmpfs&lt;&#x2F;strong&gt; (mounted at &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt;) -- A tmpfs where the kernel automatically creates device nodes for detected hardware. udev then applies rules to set permissions and create symlinks.&lt;&#x2F;p&gt;
&lt;p&gt;These pseudo-filesystems are just as &quot;real&quot; to programs as disk-backed filesystems. You open, read, and write them with the same system calls. The VFS makes them indistinguishable from files on disk.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mounting-the-root-read-only-first&quot;&gt;Mounting the Root: Read-Only First&lt;&#x2F;h2&gt;
&lt;p&gt;The kernel typically mounts the root filesystem read-only during boot. This is a safety measure. If the system crashed previously, the filesystem might have inconsistencies -- writes that were in progress when power was lost. Mounting read-only prevents further damage while the system runs a consistency check.&lt;&#x2F;p&gt;
&lt;p&gt;The init system (systemd, OpenRC, or similar) later remounts the root filesystem read-write after verifying its integrity, either through a full filesystem check (&lt;code&gt;fsck&lt;&#x2F;code&gt;) or by replaying the filesystem&#x27;s journal. Journaling filesystems like ext4, XFS, and Btrfs maintain a log of in-progress operations. Replaying this journal recovers the filesystem to a consistent state without scanning every block.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;[    3.456789] EXT4-fs (nvme0n1p2): mounted filesystem with ordered data mode. Quota mode: none.
[    4.567890] EXT4-fs (nvme0n1p2): re-mounted. Quota mode: none.
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first message shows the read-only mount. The second shows the remount as read-write. Between these two messages, the init system ran its checks and determined the filesystem was clean.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-root-to-running-system&quot;&gt;From Root to Running System&lt;&#x2F;h2&gt;
&lt;p&gt;With the root filesystem mounted read-write, the system finally has persistent storage. Programs can be loaded from &lt;code&gt;&#x2F;bin&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;usr&#x2F;bin&lt;&#x2F;code&gt;. Configuration can be read from &lt;code&gt;&#x2F;etc&lt;&#x2F;code&gt;. Logs can be written to &lt;code&gt;&#x2F;var&#x2F;log&lt;&#x2F;code&gt;. The operating system has a place to stand.&lt;&#x2F;p&gt;
&lt;p&gt;The next step is for PID 1 -- the init process that &lt;code&gt;switch_root&lt;&#x2F;code&gt; launched -- to read its configuration and start bringing up system services: networking, logging, login prompts, and everything else that turns a booted kernel into a usable machine.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;14-pid-1-init-and-systemd&#x2F;&quot;&gt;PID 1: init and systemd&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Device Drivers</title>
        <published>2025-01-16T00:00:00+00:00</published>
        <updated>2025-01-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/12-device-drivers/"/>
        <id>https://t34ch.tech/coldboot/articles/12-device-drivers/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/12-device-drivers/">&lt;p&gt;The kernel knows how to manage memory, schedule processes, and handle interrupts. But it does not inherently know how to talk to your specific network card, your particular SSD, or the exact GPU on your motherboard. Every piece of hardware has its own protocol -- its own set of registers, commands, and quirks. The software that translates between the kernel&#x27;s generic interfaces and a specific device&#x27;s protocol is called a device driver.&lt;&#x2F;p&gt;
&lt;p&gt;Without drivers, the kernel sees hardware as a collection of inscrutable chips on a circuit board. With drivers, it sees a network interface, a disk, a display. This article explains how drivers work, how they get loaded, and how the system creates the &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt; entries that let userspace programs interact with hardware.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-a-driver-actually-does&quot;&gt;What a Driver Actually Does&lt;&#x2F;h2&gt;
&lt;p&gt;Think of a driver as a translator at a diplomatic meeting. On one side is the kernel, which speaks a standard internal language: &quot;read 4096 bytes from this block device&quot; or &quot;send this packet out this network interface.&quot; On the other side is the hardware, which speaks its own proprietary language: &quot;write value 0x42 to register offset 0x18, then poll bit 3 of the status register until it goes high.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;The driver translates between these two languages. It exposes a standard interface to the kernel -- a set of function pointers that implement operations like read, write, open, and close. Inside those functions, it talks to the hardware using whatever register-level protocol the manufacturer designed.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Device driver&lt;&#x2F;strong&gt;
A piece of software that knows how to communicate with a specific piece of hardware. It implements the kernel&#x27;s standard interface for that class of device (block device, network device, character device, etc.) and translates generic requests into hardware-specific register operations.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 12a -- The driver as translator&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Userspace --&gt;
  &lt;rect x=&quot;150&quot; y=&quot;15&quot; width=&quot;280&quot; height=&quot;40&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;40&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Application: read(fd, buf, 4096)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;55&quot; x2=&quot;290&quot; y2=&quot;75&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr12)&quot;&#x2F;&gt;
  &lt;!-- Kernel generic layer --&gt;
  &lt;rect x=&quot;100&quot; y=&quot;75&quot; width=&quot;380&quot; height=&quot;40&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;100&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Kernel VFS: &quot;read 4096 bytes from block dev&quot;&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;115&quot; x2=&quot;290&quot; y2=&quot;135&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr12)&quot;&#x2F;&gt;
  &lt;!-- Driver --&gt;
  &lt;rect x=&quot;120&quot; y=&quot;135&quot; width=&quot;340&quot; height=&quot;50&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;156&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;DRIVER: nvme_read_sectors()&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;172&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Translates to NVMe command queue entries&lt;&#x2F;text&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;185&quot; x2=&quot;290&quot; y2=&quot;205&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr12)&quot;&#x2F;&gt;
  &lt;!-- Hardware --&gt;
  &lt;rect x=&quot;160&quot; y=&quot;205&quot; width=&quot;260&quot; height=&quot;45&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;225&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;NVMe SSD Controller&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;240&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Hardware registers, DMA, interrupts&lt;&#x2F;text&gt;
  &lt;!-- Side labels --&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;35&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;userspace&lt;&#x2F;text&gt;
&lt;line x1=&quot;80&quot; y1=&quot;63&quot; x2=&quot;500&quot; y2=&quot;63&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
&lt;text x=&quot;30&quot; y=&quot;105&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;kernel&lt;&#x2F;text&gt;
&lt;line x1=&quot;80&quot; y1=&quot;198&quot; x2=&quot;500&quot; y2=&quot;198&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
&lt;text x=&quot;30&quot; y=&quot;225&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;hardware&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr12&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;polygon points=&quot;0,0 8,3 0,6&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A read request flows from the application through the kernel&#x27;s generic layer to the driver, which translates it into hardware-specific operations. The driver is the only component that knows the details of the NVMe protocol.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;This layered design means the kernel does not need to be rewritten every time a new piece of hardware appears. Someone writes a driver for the new device, the driver plugs into the kernel&#x27;s standard interfaces, and everything above the driver works without modification.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;built-in-vs-loadable-modules&quot;&gt;Built-in vs. Loadable Modules&lt;&#x2F;h2&gt;
&lt;p&gt;A driver can be compiled directly into the kernel binary (built-in) or compiled as a separate file that the kernel loads at runtime (a loadable module). The choice has practical consequences.&lt;&#x2F;p&gt;
&lt;p&gt;Built-in drivers are available immediately at boot. The kernel needs certain drivers to get through early initialization -- the driver for the boot disk, for example, must be available before the kernel can mount the root filesystem. You cannot load a module from a disk you cannot yet read.&lt;&#x2F;p&gt;
&lt;p&gt;Loadable modules live in files with a &lt;code&gt;.ko&lt;&#x2F;code&gt; extension (kernel object) on the root filesystem, typically under &lt;code&gt;&#x2F;lib&#x2F;modules&#x2F;&amp;lt;kernel-version&amp;gt;&#x2F;&lt;&#x2F;code&gt;. The kernel loads them on demand -- when it detects hardware that needs a particular driver, or when an administrator explicitly requests it with &lt;code&gt;modprobe&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Loadable kernel module&lt;&#x2F;strong&gt;
A compiled driver file (.ko) that can be loaded into or removed from a running kernel without rebooting. Modules let the kernel start small and add hardware support as needed, rather than carrying every possible driver in memory at all times.
&lt;&#x2F;div&gt;
&lt;p&gt;Most Linux distributions compile a small set of essential drivers into the kernel and ship everything else as modules. A typical system has a few dozen built-in drivers and several thousand available as modules. Only the modules for hardware actually present in the system get loaded.&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ lsmod | head -5
Module                  Size  Used by
nvidia               2453504  42
snd_hda_intel          57344   4
iwlwifi               450560   1
nvme                   49152   3
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;lsmod&lt;&#x2F;code&gt; command shows currently loaded modules. Each module has a name, a size in memory, and a count of how many things are using it. A module with a use count of zero can be safely unloaded.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-device-model&quot;&gt;The Device Model&lt;&#x2F;h2&gt;
&lt;p&gt;The kernel maintains an internal model of every device in the system. This model organizes devices into a hierarchy that reflects how they are physically connected: the PCI bus hosts a network controller, which has a specific vendor and device ID, which is bound to a specific driver.&lt;&#x2F;p&gt;
&lt;p&gt;This hierarchy is exposed to userspace through the &lt;code&gt;&#x2F;sys&lt;&#x2F;code&gt; filesystem (sysfs). You can browse it to see every device the kernel knows about, which driver is bound to it, and what attributes it has.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 12b -- The device model hierarchy&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Root --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;15&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;37&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;sys&#x2F;devices&lt;&#x2F;text&gt;
  &lt;!-- Buses --&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;50&quot; x2=&quot;130&quot; y2=&quot;80&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;50&quot; x2=&quot;290&quot; y2=&quot;80&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;50&quot; x2=&quot;450&quot; y2=&quot;80&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;rect x=&quot;60&quot; y=&quot;80&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;102&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;pci0000:00&lt;&#x2F;text&gt;
  &lt;rect x=&quot;220&quot; y=&quot;80&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;102&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;platform&lt;&#x2F;text&gt;
  &lt;rect x=&quot;380&quot; y=&quot;80&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;450&quot; y=&quot;102&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;usb1&lt;&#x2F;text&gt;
  &lt;!-- PCI devices --&gt;
  &lt;line x1=&quot;90&quot; y1=&quot;115&quot; x2=&quot;70&quot; y2=&quot;145&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;115&quot; x2=&quot;170&quot; y2=&quot;145&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;15&quot; y=&quot;145&quot; width=&quot;110&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;70&quot; y=&quot;163&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0000:02:00.0&lt;&#x2F;text&gt;
  &lt;text x=&quot;70&quot; y=&quot;178&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;NVMe SSD&lt;&#x2F;text&gt;
  &lt;rect x=&quot;135&quot; y=&quot;145&quot; width=&quot;110&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;190&quot; y=&quot;163&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0000:03:00.0&lt;&#x2F;text&gt;
  &lt;text x=&quot;190&quot; y=&quot;178&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Ethernet&lt;&#x2F;text&gt;
  &lt;!-- USB devices --&gt;
  &lt;line x1=&quot;430&quot; y1=&quot;115&quot; x2=&quot;410&quot; y2=&quot;145&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;115&quot; x2=&quot;490&quot; y2=&quot;145&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;355&quot; y=&quot;145&quot; width=&quot;110&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;163&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;1-1&lt;&#x2F;text&gt;
  &lt;text x=&quot;410&quot; y=&quot;178&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Keyboard&lt;&#x2F;text&gt;
  &lt;rect x=&quot;475&quot; y=&quot;145&quot; width=&quot;110&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;530&quot; y=&quot;163&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;1-2&lt;&#x2F;text&gt;
  &lt;text x=&quot;530&quot; y=&quot;178&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Mouse&lt;&#x2F;text&gt;
  &lt;!-- Driver binding arrows --&gt;
  &lt;rect x=&quot;15&quot; y=&quot;210&quot; width=&quot;110&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;70&quot; y=&quot;229&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;nvme.ko&lt;&#x2F;text&gt;
  &lt;line x1=&quot;70&quot; y1=&quot;190&quot; x2=&quot;70&quot; y2=&quot;210&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;rect x=&quot;135&quot; y=&quot;210&quot; width=&quot;110&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;190&quot; y=&quot;229&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;e1000e.ko&lt;&#x2F;text&gt;
  &lt;line x1=&quot;190&quot; y1=&quot;190&quot; x2=&quot;190&quot; y2=&quot;210&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;rect x=&quot;355&quot; y=&quot;210&quot; width=&quot;110&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;229&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;usbhid.ko&lt;&#x2F;text&gt;
  &lt;line x1=&quot;410&quot; y1=&quot;190&quot; x2=&quot;410&quot; y2=&quot;210&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;rect x=&quot;475&quot; y=&quot;210&quot; width=&quot;110&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;530&quot; y=&quot;229&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;usbhid.ko&lt;&#x2F;text&gt;
  &lt;line x1=&quot;530&quot; y1=&quot;190&quot; x2=&quot;530&quot; y2=&quot;210&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;!-- Legend --&gt;
  &lt;rect x=&quot;100&quot; y=&quot;265&quot; width=&quot;12&quot; height=&quot;12&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
  &lt;text x=&quot;120&quot; y=&quot;276&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot;&gt;Bus&lt;&#x2F;text&gt;
  &lt;rect x=&quot;190&quot; y=&quot;265&quot; width=&quot;12&quot; height=&quot;12&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;text x=&quot;210&quot; y=&quot;276&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot;&gt;Device&lt;&#x2F;text&gt;
  &lt;rect x=&quot;290&quot; y=&quot;265&quot; width=&quot;12&quot; height=&quot;12&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;310&quot; y=&quot;276&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot;&gt;Driver&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;310&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Each device is bound to a driver. The kernel matches&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;324&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;devices to drivers using vendor&#x2F;device ID tables.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The kernel&#x27;s device model is a tree. Buses contain devices, and each device is bound to a driver. The binding is based on hardware identifiers -- the kernel looks up the device&#x27;s vendor and product ID in each driver&#x27;s supported-device table.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;When the kernel scans a bus (PCI, USB, platform) and discovers a device, it reads the device&#x27;s identifier -- typically a vendor ID and device ID pair. It then searches all registered drivers for one that claims to support that identifier. If a match is found, the kernel calls the driver&#x27;s probe function, which initializes the device and makes it available for use.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The kernel uses a match-and-bind model: devices advertise their identity, and drivers advertise which identities they support. The kernel&#x27;s bus code matches them up automatically. This is why plugging in a USB device usually &quot;just works&quot; -- the kernel finds the matching driver and binds it without manual intervention.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;dev-and-device-files&quot;&gt;&#x2F;dev and Device Files&lt;&#x2F;h2&gt;
&lt;p&gt;Unix systems represent hardware devices as files in the &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt; directory. This is one of Unix&#x27;s most powerful abstractions: programs that know how to read and write files can talk to hardware without knowing anything about how that hardware works internally.&lt;&#x2F;p&gt;
&lt;p&gt;There are two types of device files:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Block devices&lt;&#x2F;strong&gt; transfer data in fixed-size blocks. Disks and SSDs are block devices. Reading or writing any block is equally fast -- you can jump to any position without reading everything before it. Block devices are named things like &lt;code&gt;&#x2F;dev&#x2F;sda&lt;&#x2F;code&gt; (first SCSI&#x2F;SATA disk), &lt;code&gt;&#x2F;dev&#x2F;nvme0n1&lt;&#x2F;code&gt; (first NVMe SSD), and &lt;code&gt;&#x2F;dev&#x2F;sda1&lt;&#x2F;code&gt; (first partition on the first disk).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Character devices&lt;&#x2F;strong&gt; transfer data as a stream of bytes, one at a time. Serial ports, terminals, and random number generators are character devices. You read from them sequentially. &lt;code&gt;&#x2F;dev&#x2F;tty&lt;&#x2F;code&gt; (the current terminal), &lt;code&gt;&#x2F;dev&#x2F;null&lt;&#x2F;code&gt; (discards everything written to it), and &lt;code&gt;&#x2F;dev&#x2F;urandom&lt;&#x2F;code&gt; (produces random bytes) are all character devices.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Device file (device node)&lt;&#x2F;strong&gt;
A special file in &#x2F;dev that represents a hardware device or virtual device. Programs interact with hardware by opening, reading, writing, and closing these files using standard file operations. The kernel maps these file operations to the appropriate driver functions.
&lt;&#x2F;div&gt;
&lt;p&gt;Each device file has two numbers associated with it: a major number and a minor number. The major number identifies which driver handles the device. The minor number identifies which specific device that driver manages. You can see these numbers with &lt;code&gt;ls -l&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls -l &#x2F;dev&#x2F;sda
brw-rw---- 1 root disk 8, 0 Jan 14 10:00 &#x2F;dev&#x2F;sda
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;8, 0&lt;&#x2F;code&gt; means major 8 (the sd driver), minor 0 (the first disk). &lt;code&gt;&#x2F;dev&#x2F;sda1&lt;&#x2F;code&gt; would be &lt;code&gt;8, 1&lt;&#x2F;code&gt; -- same driver, different minor number for the first partition.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;udev-populating-dev-dynamically&quot;&gt;udev: Populating &#x2F;dev Dynamically&lt;&#x2F;h2&gt;
&lt;p&gt;In early Linux systems, &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt; was a static directory containing thousands of device files for every conceivable piece of hardware, whether or not it was actually present. This was wasteful and confusing.&lt;&#x2F;p&gt;
&lt;p&gt;Modern Linux uses &lt;strong&gt;udev&lt;&#x2F;strong&gt;, a userspace daemon that creates and removes device files dynamically as hardware appears and disappears. When the kernel detects a new device -- at boot or when you plug something in -- it sends an event called a uevent. udev receives this event and creates the appropriate &lt;code&gt;&#x2F;dev&lt;&#x2F;code&gt; entry.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 12c -- udev device creation flow&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Step 1: Hardware detected --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;20&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;42&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;1. HARDWARE&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;58&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;USB drive plugged in&lt;&#x2F;text&gt;
  &lt;line x1=&quot;180&quot; y1=&quot;45&quot; x2=&quot;210&quot; y2=&quot;45&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr12c)&quot;&#x2F;&gt;
  &lt;!-- Step 2: Kernel detects --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;20&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;42&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;2. KERNEL&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;58&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Binds usb-storage driver&lt;&#x2F;text&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;45&quot; x2=&quot;400&quot; y2=&quot;45&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr12c)&quot;&#x2F;&gt;
  &lt;!-- Step 3: uevent --&gt;
  &lt;rect x=&quot;400&quot; y=&quot;20&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;42&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;3. UEVENT&lt;&#x2F;text&gt;
  &lt;text x=&quot;480&quot; y=&quot;58&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;add@&#x2F;block&#x2F;sdb&lt;&#x2F;text&gt;
  &lt;!-- Arrow down --&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;70&quot; x2=&quot;480&quot; y2=&quot;100&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr12c)&quot;&#x2F;&gt;
  &lt;!-- Step 4: udev receives --&gt;
  &lt;rect x=&quot;320&quot; y=&quot;100&quot; width=&quot;300&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;470&quot; y=&quot;120&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;4. UDEV DAEMON (userspace)&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;136&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Receives uevent via netlink socket&lt;&#x2F;text&gt;
  &lt;!-- Arrow down --&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;150&quot; x2=&quot;470&quot; y2=&quot;175&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr12c)&quot;&#x2F;&gt;
  &lt;!-- Step 5: Rules processing --&gt;
  &lt;rect x=&quot;300&quot; y=&quot;175&quot; width=&quot;260&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;195&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;5. APPLY RULES&lt;&#x2F;text&gt;
  &lt;text x=&quot;430&quot; y=&quot;211&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;etc&#x2F;udev&#x2F;rules.d&#x2F;*.rules&lt;&#x2F;text&gt;
  &lt;!-- Arrow left --&gt;
  &lt;line x1=&quot;300&quot; y1=&quot;200&quot; x2=&quot;225&quot; y2=&quot;200&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr12c)&quot;&#x2F;&gt;
  &lt;!-- Step 6: Create device node --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;175&quot; width=&quot;200&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;120&quot; y=&quot;195&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;6. CREATE &#x2F;dev&#x2F;sdb&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;211&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;mknod, set permissions&lt;&#x2F;text&gt;
  &lt;!-- Symlinks --&gt;
  &lt;line x1=&quot;120&quot; y1=&quot;225&quot; x2=&quot;120&quot; y2=&quot;255&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;rect x=&quot;20&quot; y=&quot;255&quot; width=&quot;260&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;150&quot; y=&quot;275&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Symlinks: &#x2F;dev&#x2F;disk&#x2F;by-uuid&#x2F;..., &#x2F;dev&#x2F;disk&#x2F;by-label&#x2F;...&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr12c&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;polygon points=&quot;0,0 8,3 0,6&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;When hardware appears, the kernel sends a uevent. udev receives it, applies rules to determine the device name and permissions, creates the &#x2F;dev entry, and optionally creates symlinks for stable naming.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;udev also applies rules that control the device name, its permissions, and any symlinks. For example, udev rules create the stable symlinks under &lt;code&gt;&#x2F;dev&#x2F;disk&#x2F;by-uuid&#x2F;&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;dev&#x2F;disk&#x2F;by-id&#x2F;&lt;&#x2F;code&gt; that let you refer to a disk by its unique identifier rather than a name like &lt;code&gt;sda&lt;&#x2F;code&gt; that might change between boots.&lt;&#x2F;p&gt;
&lt;p&gt;The rules files live in &lt;code&gt;&#x2F;etc&#x2F;udev&#x2F;rules.d&#x2F;&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;lib&#x2F;udev&#x2F;rules.d&#x2F;&lt;&#x2F;code&gt;. A rule looks like this:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;SUBSYSTEM==&amp;quot;block&amp;quot;, ATTR{size}!=&amp;quot;0&amp;quot;, ENV{ID_SERIAL}==&amp;quot;?*&amp;quot;, \
  SYMLINK+=&amp;quot;disk&#x2F;by-id&#x2F;$env{ID_BUS}-$env{ID_SERIAL}&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This says: for any block device with a non-zero size and a serial number, create a symlink using the bus type and serial number. This is how &lt;code&gt;&#x2F;dev&#x2F;disk&#x2F;by-id&#x2F;ata-Samsung_SSD_860_S3Z9NB0K123456&lt;&#x2F;code&gt; gets created.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-drivers-talk-to-hardware&quot;&gt;How Drivers Talk to Hardware&lt;&#x2F;h2&gt;
&lt;p&gt;At the lowest level, drivers communicate with hardware through two mechanisms: memory-mapped I&#x2F;O and port I&#x2F;O.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Memory-mapped I&#x2F;O (MMIO)&lt;&#x2F;strong&gt; maps a device&#x27;s registers into the system&#x27;s address space. The driver reads and writes to specific memory addresses, but those addresses do not correspond to RAM -- they are wired to the device&#x27;s control registers. Writing to address 0xFEA00004 might tell a network card to start transmitting. Reading from it might return the card&#x27;s status.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Port I&#x2F;O (PIO)&lt;&#x2F;strong&gt; uses special CPU instructions (&lt;code&gt;in&lt;&#x2F;code&gt; and &lt;code&gt;out&lt;&#x2F;code&gt; on x86) to communicate with devices through a separate I&#x2F;O address space. This is an older mechanism, mostly used by legacy devices like PS&#x2F;2 keyboards and serial ports.&lt;&#x2F;p&gt;
&lt;p&gt;Modern high-performance devices also use DMA -- Direct Memory Access. Instead of the CPU reading data from the device one word at a time, the device writes directly into RAM without CPU involvement. The CPU sets up a DMA transfer by telling the device where in memory to write, then does other work while the transfer happens. When the device finishes, it fires an interrupt to let the CPU know the data is ready.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Drivers bridge the gap between the kernel&#x27;s abstract view of hardware (block devices, network interfaces, character devices) and the physical reality of register addresses, DMA buffers, and interrupt lines. The driver model lets the rest of the system treat all devices uniformly, regardless of how different they are at the hardware level.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-class-system&quot;&gt;The Class System&lt;&#x2F;h2&gt;
&lt;p&gt;Devices are also organized into classes based on their function. All network interfaces -- whether Ethernet, Wi-Fi, or cellular -- belong to the &lt;code&gt;net&lt;&#x2F;code&gt; class. All block storage devices belong to the &lt;code&gt;block&lt;&#x2F;code&gt; class. All input devices belong to the &lt;code&gt;input&lt;&#x2F;code&gt; class.&lt;&#x2F;p&gt;
&lt;p&gt;Classes let userspace tools work with devices by function rather than by physical connection. The &lt;code&gt;ip&lt;&#x2F;code&gt; command does not care whether your network interface is PCI, USB, or virtual. It uses the &lt;code&gt;net&lt;&#x2F;code&gt; class interface. The &lt;code&gt;mount&lt;&#x2F;code&gt; command does not care whether your disk is NVMe, SATA, or a network block device. It uses the &lt;code&gt;block&lt;&#x2F;code&gt; class interface.&lt;&#x2F;p&gt;
&lt;p&gt;You can see device classes in &lt;code&gt;&#x2F;sys&#x2F;class&#x2F;&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ ls &#x2F;sys&#x2F;class&#x2F;
block   dmi     hwmon   misc    net     scsi_device   tty
dma     gpio    input   mmc     pci_bus scsi_host     usb
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each directory contains symlinks to every device of that class, regardless of how it is physically connected.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;drivers-during-boot&quot;&gt;Drivers During Boot&lt;&#x2F;h2&gt;
&lt;p&gt;During the boot sequence, driver loading happens in two waves.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Wave 1: Built-in drivers.&lt;&#x2F;strong&gt; As the kernel initializes, it runs the init functions of all built-in drivers. These include drivers for the CPU itself, the interrupt controllers, the system timer, and the memory controller. Without these, nothing else can function.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Wave 2: Module loading.&lt;&#x2F;strong&gt; Once the kernel has mounted enough of a filesystem to read module files (typically from initramfs, which we cover in the next article), it can load additional drivers on demand. The kernel detects hardware on PCI, USB, and other buses, matches device IDs to module alias strings, and calls &lt;code&gt;modprobe&lt;&#x2F;code&gt; to load the right module.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 12d -- Driver loading timeline during boot&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 220&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;220&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Timeline --&gt;
  &lt;line x1=&quot;40&quot; y1=&quot;50&quot; x2=&quot;540&quot; y2=&quot;50&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;545,50 535,45 535,55&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;!-- Time markers --&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;45&quot; x2=&quot;60&quot; y2=&quot;55&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;60&quot; y=&quot;40&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;0s&lt;&#x2F;text&gt;
  &lt;line x1=&quot;200&quot; y1=&quot;45&quot; x2=&quot;200&quot; y2=&quot;55&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;200&quot; y=&quot;40&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;~0.5s&lt;&#x2F;text&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;45&quot; x2=&quot;340&quot; y2=&quot;55&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;340&quot; y=&quot;40&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;~1.5s&lt;&#x2F;text&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;45&quot; x2=&quot;480&quot; y2=&quot;55&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;40&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;~3s&lt;&#x2F;text&gt;
  &lt;!-- Wave 1: Built-in --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;65&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;87&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;BUILT-IN DRIVERS&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;70&quot; y=&quot;120&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;CPU, IRQ, timer,&lt;&#x2F;text&gt;
&lt;text x=&quot;70&quot; y=&quot;132&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;memory controller,&lt;&#x2F;text&gt;
&lt;text x=&quot;70&quot; y=&quot;144&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;early console&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- initramfs mount --&gt;
  &lt;line x1=&quot;200&quot; y1=&quot;55&quot; x2=&quot;200&quot; y2=&quot;65&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;200&quot; y=&quot;78&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;initramfs&lt;&#x2F;text&gt;
  &lt;text x=&quot;200&quot; y=&quot;90&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;mounted&lt;&#x2F;text&gt;
  &lt;!-- Wave 2: Modules --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;65&quot; width=&quot;180&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;rgba(0,191,255,0.15)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;310&quot; y=&quot;87&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;MODULE LOADING&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;230&quot; y=&quot;120&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;Storage drivers,&lt;&#x2F;text&gt;
&lt;text x=&quot;230&quot; y=&quot;132&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;filesystem modules,&lt;&#x2F;text&gt;
&lt;text x=&quot;230&quot; y=&quot;144&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;network, GPU, USB&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Root mount and udev --&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;55&quot; x2=&quot;340&quot; y2=&quot;65&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;340&quot; y=&quot;78&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;root&lt;&#x2F;text&gt;
  &lt;text x=&quot;340&quot; y=&quot;90&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;mounted&lt;&#x2F;text&gt;
  &lt;!-- Wave 3: Late modules --&gt;
  &lt;rect x=&quot;360&quot; y=&quot;65&quot; width=&quot;140&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;87&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;LATE MODULES&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;370&quot; y=&quot;120&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;Bluetooth, audio,&lt;&#x2F;text&gt;
&lt;text x=&quot;370&quot; y=&quot;132&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;webcam, sensors,&lt;&#x2F;text&gt;
&lt;text x=&quot;370&quot; y=&quot;144&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;additional USB&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- udev label --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;165&quot; width=&quot;300&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;370&quot; y=&quot;184&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;udev processes events, creates &#x2F;dev entries&lt;&#x2F;text&gt;
  &lt;line x1=&quot;310&quot; y1=&quot;100&quot; x2=&quot;370&quot; y2=&quot;165&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Driver loading happens in waves. Built-in drivers run immediately. Modules load once the initramfs is available. Additional modules load after the real root filesystem is mounted.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;This staged loading is a chicken-and-egg solution. You need a storage driver to read module files from disk, but the storage driver itself might be a module. The answer is initramfs -- a temporary root filesystem loaded into RAM by the bootloader that contains the essential modules needed to access the real root. We cover initramfs in the next article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;debugging-driver-problems&quot;&gt;Debugging Driver Problems&lt;&#x2F;h2&gt;
&lt;p&gt;When a device does not work, the first place to look is the kernel log:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;$ dmesg | grep -i error
[    2.345] e1000e: probe of 0000:03:00.0 failed with error -5
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;-5&lt;&#x2F;code&gt; is &lt;code&gt;EIO&lt;&#x2F;code&gt; -- an I&#x2F;O error during probe. The kernel also provides diagnostic information through &lt;code&gt;&#x2F;sys&lt;&#x2F;code&gt;. Every device directory in sysfs contains files like &lt;code&gt;vendor&lt;&#x2F;code&gt;, &lt;code&gt;device&lt;&#x2F;code&gt;, &lt;code&gt;driver&lt;&#x2F;code&gt;, and &lt;code&gt;uevent&lt;&#x2F;code&gt; that tell you exactly what the kernel sees and which driver (if any) is bound.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;lspci -v&lt;&#x2F;code&gt; and &lt;code&gt;lsusb -v&lt;&#x2F;code&gt; show detailed information about every PCI and USB device, including which driver is currently bound. If a device shows no driver, either the right module is not loaded or no driver exists for that hardware.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: probe&lt;&#x2F;strong&gt;
The function a driver calls to check whether it can handle a specific device and, if so, to initialize it. If probe succeeds, the driver is bound to the device. If it fails, the kernel tries other drivers or leaves the device unbound.
&lt;&#x2F;div&gt;
&lt;p&gt;Drivers are the nervous system of the operating system. They bridge the abstract world of file operations and network sockets with the physical world of voltage levels, register writes, and DMA transfers. Every time you read a file, send a packet, or hear a sound, a driver is doing the translation.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;13-the-root-filesystem&#x2F;&quot;&gt;The Root Filesystem&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Clock Signal</title>
        <published>2025-01-15T00:00:00+00:00</published>
        <updated>2025-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/11b-the-clock-signal/"/>
        <id>https://t34ch.tech/coldboot/articles/11b-the-clock-signal/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/11b-the-clock-signal/">&lt;p&gt;A CPU does not run continuously like water through a pipe. It advances in steps, like a marching band. Every step happens at the same instant, synchronized across billions of transistors. The thing that keeps them in lockstep is the clock signal -- a voltage that swings between high and low at a precise, unwavering frequency.&lt;&#x2F;p&gt;
&lt;p&gt;Without a clock, the CPU would not know when to read an instruction, when to add two numbers, or when to write a result to memory. The clock is the heartbeat of the machine. This article explains where it comes from, how it reaches every part of the processor, and what &quot;clock speed&quot; actually means.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-crystal-oscillator&quot;&gt;The Crystal Oscillator&lt;&#x2F;h2&gt;
&lt;p&gt;The master clock starts with a small piece of quartz crystal, usually mounted in a metal can on the motherboard. Quartz has a useful physical property: when you apply voltage across it, it vibrates at a very precise frequency. This is the piezoelectric effect -- mechanical stress produces voltage, and voltage produces mechanical stress.&lt;&#x2F;p&gt;
&lt;p&gt;The crystal is cut to a specific shape and thickness that determines its natural resonant frequency. A typical motherboard crystal vibrates at around 25 MHz -- 25 million cycles per second. This is far slower than the CPU&#x27;s final clock speed, but it is the starting point.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Crystal oscillator&lt;&#x2F;strong&gt;
A circuit that uses the piezoelectric properties of a quartz crystal to generate an electrical signal at a very precise frequency. It provides the base timing reference for the entire computer. The frequency is stable across temperature changes and does not drift significantly over time.
&lt;&#x2F;div&gt;
&lt;p&gt;Think of the crystal as a tuning fork. Strike a tuning fork and it vibrates at exactly 440 Hz every time, regardless of how hard you hit it. The quartz crystal does the same thing electrically. It produces a clean, stable wave that the rest of the system can rely on.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 11b-a -- From crystal to CPU clock&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 200&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;200&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Crystal --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;60&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;70&quot; y=&quot;82&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;CRYSTAL&lt;&#x2F;text&gt;
  &lt;text x=&quot;70&quot; y=&quot;98&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;25 MHz&lt;&#x2F;text&gt;
  &lt;!-- Arrow --&gt;
  &lt;line x1=&quot;120&quot; y1=&quot;85&quot; x2=&quot;155&quot; y2=&quot;85&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowClk)&quot;&#x2F;&gt;
  &lt;!-- PLL --&gt;
  &lt;rect x=&quot;155&quot; y=&quot;50&quot; width=&quot;120&quot; height=&quot;70&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;215&quot; y=&quot;78&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;PLL&lt;&#x2F;text&gt;
  &lt;text x=&quot;215&quot; y=&quot;95&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;multiply x160&lt;&#x2F;text&gt;
  &lt;!-- Arrow --&gt;
  &lt;line x1=&quot;275&quot; y1=&quot;85&quot; x2=&quot;310&quot; y2=&quot;85&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowClk)&quot;&#x2F;&gt;
  &lt;!-- Clock generator --&gt;
  &lt;rect x=&quot;310&quot; y=&quot;40&quot; width=&quot;120&quot; height=&quot;90&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;370&quot; y=&quot;68&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;CLOCK GEN&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;85&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;4.0 GHz base&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;100&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;dividers for&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;113&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;each domain&lt;&#x2F;text&gt;
  &lt;!-- Output arrows --&gt;
  &lt;line x1=&quot;430&quot; y1=&quot;60&quot; x2=&quot;480&quot; y2=&quot;40&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowClk)&quot;&#x2F;&gt;
  &lt;line x1=&quot;430&quot; y1=&quot;85&quot; x2=&quot;480&quot; y2=&quot;85&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowClk)&quot;&#x2F;&gt;
  &lt;line x1=&quot;430&quot; y1=&quot;110&quot; x2=&quot;480&quot; y2=&quot;130&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowClk)&quot;&#x2F;&gt;
  &lt;!-- Output labels --&gt;
&lt;p&gt;&lt;text x=&quot;490&quot; y=&quot;43&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;CPU cores 4.0 GHz&lt;&#x2F;text&gt;
&lt;text x=&quot;490&quot; y=&quot;88&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;Memory 1.6 GHz&lt;&#x2F;text&gt;
&lt;text x=&quot;490&quot; y=&quot;133&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;PCIe 100 MHz&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Waveform hint under crystal --&gt;
&lt;p&gt;&lt;polyline points=&quot;30,155 40,145 50,155 60,145 70,155 80,145 90,155 100,145 110,155&quot;
            fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
&lt;text x=&quot;70&quot; y=&quot;175&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;25 MHz base wave&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrowClk&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;polygon points=&quot;0,0 8,3 0,6&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The crystal provides a stable 25 MHz reference. A PLL multiplies this up to the CPU&#x27;s operating frequency. A clock generator then divides this down to produce different frequencies for different parts of the system.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-phase-locked-loop&quot;&gt;The Phase-Locked Loop&lt;&#x2F;h2&gt;
&lt;p&gt;A 25 MHz crystal cannot directly clock a 4 GHz processor. You need a frequency multiplier. That is the job of the Phase-Locked Loop, or PLL.&lt;&#x2F;p&gt;
&lt;p&gt;A PLL is a feedback circuit that takes a low-frequency reference signal and generates a higher-frequency output that stays locked in phase with the input. &quot;Locked in phase&quot; means the output signal&#x27;s edges line up precisely with the input signal&#x27;s edges -- they do not drift apart over time.&lt;&#x2F;p&gt;
&lt;p&gt;Here is the basic idea. The PLL contains a voltage-controlled oscillator (VCO) that can run at high frequencies but is not very stable on its own. A feedback circuit divides the VCO&#x27;s output frequency down and compares it with the crystal&#x27;s reference signal. If the divided-down output runs too fast, the circuit slows the VCO. If it runs too slow, the circuit speeds it up. This feedback loop keeps the output frequency at an exact multiple of the reference.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Phase-Locked Loop (PLL)&lt;&#x2F;strong&gt;
A feedback circuit that generates a high-frequency output signal locked to a lower-frequency reference. The output frequency is a precise integer multiple of the input. PLLs are used throughout a computer to create the various clock frequencies that different components need.
&lt;&#x2F;div&gt;
&lt;p&gt;To get 4.0 GHz from a 25 MHz crystal, the PLL uses a multiplication factor of 160. The result is a high-frequency clock that is just as stable as the crystal, because any drift is immediately corrected by the feedback loop.&lt;&#x2F;p&gt;
&lt;p&gt;Modern CPUs contain multiple PLLs. One generates the core clock. Others generate clocks for the memory controller, the PCIe bus, and the integrated GPU. Each runs at a different frequency, but all are ultimately derived from the same crystal reference.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-clock-tree&quot;&gt;The Clock Tree&lt;&#x2F;h2&gt;
&lt;p&gt;The PLL produces a single clock signal at the target frequency. But a modern CPU die has billions of transistors spread across several square centimeters. The clock must reach every one of them at nearly the same instant. A delay of even a fraction of a nanosecond between two parts of the chip can cause incorrect computation.&lt;&#x2F;p&gt;
&lt;p&gt;The network of wires and buffers that distributes the clock signal across the chip is called the clock tree. It is one of the most carefully engineered structures in the processor.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 11b-b -- Clock tree distribution&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- PLL source --&gt;
  &lt;rect x=&quot;240&quot; y=&quot;15&quot; width=&quot;100&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;37&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;PLL OUTPUT&lt;&#x2F;text&gt;
  &lt;!-- Level 1 buffers --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;50&quot; x2=&quot;290&quot; y2=&quot;75&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;75&quot; x2=&quot;435&quot; y2=&quot;75&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;75&quot; x2=&quot;145&quot; y2=&quot;95&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;75&quot; x2=&quot;290&quot; y2=&quot;95&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;line x1=&quot;435&quot; y1=&quot;75&quot; x2=&quot;435&quot; y2=&quot;95&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;rect x=&quot;120&quot; y=&quot;95&quot; width=&quot;50&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;112&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;rect x=&quot;265&quot; y=&quot;95&quot; width=&quot;50&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;112&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;rect x=&quot;410&quot; y=&quot;95&quot; width=&quot;50&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;112&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;!-- Level 2 --&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;120&quot; x2=&quot;145&quot; y2=&quot;140&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;80&quot; y1=&quot;140&quot; x2=&quot;210&quot; y2=&quot;140&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;80&quot; y1=&quot;140&quot; x2=&quot;80&quot; y2=&quot;155&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;210&quot; y1=&quot;140&quot; x2=&quot;210&quot; y2=&quot;155&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;120&quot; x2=&quot;290&quot; y2=&quot;140&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;140&quot; x2=&quot;340&quot; y2=&quot;140&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;140&quot; x2=&quot;240&quot; y2=&quot;155&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;140&quot; x2=&quot;340&quot; y2=&quot;155&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;435&quot; y1=&quot;120&quot; x2=&quot;435&quot; y2=&quot;140&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;140&quot; x2=&quot;500&quot; y2=&quot;140&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;140&quot; x2=&quot;370&quot; y2=&quot;155&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;500&quot; y1=&quot;140&quot; x2=&quot;500&quot; y2=&quot;155&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- Level 2 buffers --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;155&quot; width=&quot;40&quot; height=&quot;20&quot; rx=&quot;2&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;169&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;rect x=&quot;190&quot; y=&quot;155&quot; width=&quot;40&quot; height=&quot;20&quot; rx=&quot;2&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;210&quot; y=&quot;169&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;rect x=&quot;220&quot; y=&quot;155&quot; width=&quot;40&quot; height=&quot;20&quot; rx=&quot;2&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;240&quot; y=&quot;169&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;rect x=&quot;320&quot; y=&quot;155&quot; width=&quot;40&quot; height=&quot;20&quot; rx=&quot;2&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;340&quot; y=&quot;169&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;rect x=&quot;350&quot; y=&quot;155&quot; width=&quot;40&quot; height=&quot;20&quot; rx=&quot;2&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;370&quot; y=&quot;169&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;rect x=&quot;480&quot; y=&quot;155&quot; width=&quot;40&quot; height=&quot;20&quot; rx=&quot;2&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;500&quot; y=&quot;169&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;BUF&lt;&#x2F;text&gt;
  &lt;!-- Transistor destinations --&gt;
  &lt;line x1=&quot;80&quot; y1=&quot;175&quot; x2=&quot;80&quot; y2=&quot;195&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;210&quot; y1=&quot;175&quot; x2=&quot;210&quot; y2=&quot;195&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;175&quot; x2=&quot;240&quot; y2=&quot;195&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;175&quot; x2=&quot;340&quot; y2=&quot;195&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;370&quot; y1=&quot;175&quot; x2=&quot;370&quot; y2=&quot;195&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;500&quot; y1=&quot;175&quot; x2=&quot;500&quot; y2=&quot;195&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;!-- Chip regions --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;195&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;rgba(0,191,255,0.08)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;225&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;ALU&lt;&#x2F;text&gt;
  &lt;rect x=&quot;170&quot; y=&quot;195&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;rgba(255,215,0,0.08)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;220&quot; y=&quot;225&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;REGISTERS&lt;&#x2F;text&gt;
  &lt;rect x=&quot;300&quot; y=&quot;195&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;rgba(255,102,0,0.08)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;350&quot; y=&quot;225&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;CACHE&lt;&#x2F;text&gt;
  &lt;rect x=&quot;430&quot; y=&quot;195&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;rgba(57,211,83,0.08)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;485&quot; y=&quot;225&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;SCHEDULER&lt;&#x2F;text&gt;
  &lt;!-- Legend --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;275&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;The clock fans out in a balanced tree.&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;291&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Each path from PLL to transistor has&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;307&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;the same length and same delay.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The clock tree fans out from the PLL through multiple levels of buffers. Engineers design each branch to have equal propagation delay, so the clock edge arrives everywhere on the chip at the same time.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The tree is designed so that every path from the PLL to any transistor has the same electrical length. This property is called clock skew minimization. If one corner of the chip received the clock edge 0.1 nanoseconds before another corner, those two regions would briefly disagree about what &quot;now&quot; is, and logic that depends on both regions would produce wrong answers.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The clock tree is one of the most critical structures on a CPU die. It must deliver the clock signal to billions of transistors with nearly zero timing difference between any two points. Getting this wrong by even a fraction of a nanosecond causes computation errors.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-happens-on-a-clock-edge&quot;&gt;What Happens on a Clock Edge&lt;&#x2F;h2&gt;
&lt;p&gt;The clock signal is a square wave -- it swings between low and high voltage at the clock frequency. Each transition from low to high is called the rising edge. Most digital logic is designed to do its work on the rising edge.&lt;&#x2F;p&gt;
&lt;p&gt;On each rising edge, a cascade of events happens simultaneously across the chip:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Flip-flops capture the values on their input wires and store them.&lt;&#x2F;li&gt;
&lt;li&gt;The stored values propagate through combinational logic (adders, multiplexers, comparators).&lt;&#x2F;li&gt;
&lt;li&gt;The results settle on the input wires of the next stage of flip-flops.&lt;&#x2F;li&gt;
&lt;li&gt;On the next rising edge, those results are captured, and the cycle repeats.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Flip-flop&lt;&#x2F;strong&gt;
A circuit element that captures and stores one bit of data on the rising (or falling) edge of the clock signal. Between edges, it holds its value steady regardless of what happens on its input. Flip-flops are the basic storage elements inside a processor -- registers, pipeline stages, and caches are all built from them.
&lt;&#x2F;div&gt;
&lt;p&gt;This is why clock speed matters. A 4 GHz clock produces 4 billion rising edges per second. Each edge advances the processor&#x27;s state by one step. More edges per second means more steps per second means more work done.&lt;&#x2F;p&gt;
&lt;p&gt;But there is a limit. After each clock edge, the signals must propagate through logic gates and settle to stable values before the next edge arrives. If the clock runs too fast, the signals have not finished settling when the next edge captures them, and the processor computes garbage. This is why you cannot simply crank up the clock speed indefinitely -- the physics of signal propagation through transistors sets an upper bound.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;clock-speed-vs-instructions-per-cycle&quot;&gt;Clock Speed vs. Instructions Per Cycle&lt;&#x2F;h2&gt;
&lt;p&gt;Clock speed alone does not determine how fast a processor runs. Two processors at the same clock speed can have very different performance. The other half of the equation is instructions per cycle (IPC) -- how much useful work the processor completes in each clock tick.&lt;&#x2F;p&gt;
&lt;p&gt;A simple processor might take five clock cycles to execute one instruction: one cycle to fetch it, one to decode it, one to read registers, one to execute, and one to write the result back. That processor has an IPC of 0.2.&lt;&#x2F;p&gt;
&lt;p&gt;A modern superscalar processor can execute multiple instructions simultaneously by using parallel execution units. It might complete four or more instructions every cycle, giving it an IPC of 4 or higher. This is why a modern 4 GHz chip vastly outperforms a 4 GHz chip from 2005 -- the modern chip does far more work per tick.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 11b-c -- Clock cycles and instruction execution&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Clock signal --&gt;
&lt;p&gt;&lt;text x=&quot;50&quot; y=&quot;30&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;CLK&lt;&#x2F;text&gt;
&lt;polyline points=&quot;60,35 60,15 110,15 110,35 160,35 160,15 210,15 210,35 260,35 260,15 310,15 310,35 360,35 360,15 410,15 410,35 460,35 460,15 510,15 510,35 540,35&quot;
            fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
  &lt;!-- Cycle labels --&gt;
&lt;p&gt;&lt;text x=&quot;85&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C1&lt;&#x2F;text&gt;
&lt;text x=&quot;135&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C2&lt;&#x2F;text&gt;
&lt;text x=&quot;185&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C3&lt;&#x2F;text&gt;
&lt;text x=&quot;235&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C4&lt;&#x2F;text&gt;
&lt;text x=&quot;285&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C5&lt;&#x2F;text&gt;
&lt;text x=&quot;335&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C6&lt;&#x2F;text&gt;
&lt;text x=&quot;385&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C7&lt;&#x2F;text&gt;
&lt;text x=&quot;435&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C8&lt;&#x2F;text&gt;
&lt;text x=&quot;485&quot; y=&quot;52&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;C9&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Simple CPU label --&gt;
&lt;p&gt;&lt;text x=&quot;20&quot; y=&quot;85&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;Simple&lt;&#x2F;text&gt;
&lt;text x=&quot;20&quot; y=&quot;98&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;CPU:&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Simple CPU: 1 instruction takes 5 cycles --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;70&quot; width=&quot;250&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;85&quot; y=&quot;88&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;FETCH&lt;&#x2F;text&gt;
  &lt;text x=&quot;135&quot; y=&quot;88&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;DEC&lt;&#x2F;text&gt;
  &lt;text x=&quot;185&quot; y=&quot;88&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;READ&lt;&#x2F;text&gt;
  &lt;text x=&quot;235&quot; y=&quot;88&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;EXEC&lt;&#x2F;text&gt;
  &lt;text x=&quot;275&quot; y=&quot;88&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot;&gt;WRITE&lt;&#x2F;text&gt;
  &lt;rect x=&quot;310&quot; y=&quot;70&quot; width=&quot;200&quot; height=&quot;28&quot; rx=&quot;3&quot; fill=&quot;rgba(255,102,0,0.08)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;88&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;instr #2 begins...&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;555&quot; y=&quot;88&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;IPC: 0.2&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Pipelined CPU label --&gt;
&lt;p&gt;&lt;text x=&quot;20&quot; y=&quot;140&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;Pipelined&lt;&#x2F;text&gt;
&lt;text x=&quot;20&quot; y=&quot;153&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;CPU:&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Pipelined: overlapping instructions --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;125&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(0,191,255,0.2)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;85&quot; y=&quot;140&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;F&lt;&#x2F;text&gt;
  &lt;rect x=&quot;110&quot; y=&quot;125&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(0,191,255,0.15)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;135&quot; y=&quot;140&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;D&lt;&#x2F;text&gt;
  &lt;rect x=&quot;160&quot; y=&quot;125&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(0,191,255,0.10)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;185&quot; y=&quot;140&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;R&lt;&#x2F;text&gt;
  &lt;rect x=&quot;210&quot; y=&quot;125&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(0,191,255,0.08)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;140&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;E&lt;&#x2F;text&gt;
  &lt;rect x=&quot;260&quot; y=&quot;125&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(0,191,255,0.05)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;285&quot; y=&quot;140&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;W&lt;&#x2F;text&gt;
  &lt;rect x=&quot;110&quot; y=&quot;149&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.2)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;135&quot; y=&quot;164&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;F&lt;&#x2F;text&gt;
  &lt;rect x=&quot;160&quot; y=&quot;149&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;185&quot; y=&quot;164&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;D&lt;&#x2F;text&gt;
  &lt;rect x=&quot;210&quot; y=&quot;149&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.10)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;164&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;R&lt;&#x2F;text&gt;
  &lt;rect x=&quot;260&quot; y=&quot;149&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.08)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;285&quot; y=&quot;164&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;E&lt;&#x2F;text&gt;
  &lt;rect x=&quot;310&quot; y=&quot;149&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.05)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;335&quot; y=&quot;164&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;W&lt;&#x2F;text&gt;
  &lt;rect x=&quot;160&quot; y=&quot;173&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(255,215,0,0.2)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;185&quot; y=&quot;188&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;F&lt;&#x2F;text&gt;
  &lt;rect x=&quot;210&quot; y=&quot;173&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;188&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;D&lt;&#x2F;text&gt;
  &lt;rect x=&quot;260&quot; y=&quot;173&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(255,215,0,0.10)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;285&quot; y=&quot;188&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;R&lt;&#x2F;text&gt;
  &lt;rect x=&quot;310&quot; y=&quot;173&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(255,215,0,0.08)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;335&quot; y=&quot;188&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;E&lt;&#x2F;text&gt;
  &lt;rect x=&quot;360&quot; y=&quot;173&quot; width=&quot;50&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;rgba(255,215,0,0.05)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;385&quot; y=&quot;188&quot; fill=&quot;#EEECE6&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;W&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;555&quot; y=&quot;164&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;IPC: 1.0&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Superscalar label --&gt;
&lt;p&gt;&lt;text x=&quot;20&quot; y=&quot;222&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;Super-&lt;&#x2F;text&gt;
&lt;text x=&quot;20&quot; y=&quot;235&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;scalar:&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Superscalar: multiple instructions per cycle --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;210&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.2)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;60&quot; y=&quot;229&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.2)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;60&quot; y=&quot;248&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.2)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;110&quot; y=&quot;210&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;110&quot; y=&quot;229&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;110&quot; y=&quot;248&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;160&quot; y=&quot;210&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.10)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;160&quot; y=&quot;229&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.10)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;160&quot; y=&quot;248&quot; width=&quot;50&quot; height=&quot;18&quot; rx=&quot;2&quot; fill=&quot;rgba(57,211,83,0.10)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;555&quot; y=&quot;240&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;IPC: 3.0+&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Three execution models at the same clock speed. A simple CPU completes one instruction every five cycles (IPC 0.2). A pipelined CPU overlaps stages to reach IPC 1.0. A superscalar CPU executes multiple instructions per cycle.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The formula for raw throughput is simple:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Performance = Clock Speed x IPC&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A 4 GHz processor with IPC 4 completes 16 billion operations per second. A 5 GHz processor with IPC 2 completes only 10 billion. The slower clock wins because it does more per tick. This is why &quot;GHz wars&quot; ended around 2005 -- chip designers realized that increasing IPC was a more efficient path to performance than increasing clock speed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;clock-domains-and-crossing-boundaries&quot;&gt;Clock Domains and Crossing Boundaries&lt;&#x2F;h2&gt;
&lt;p&gt;Not everything in a computer runs at the same frequency. The CPU cores might run at 4 GHz, but the memory bus runs at 1.6 GHz, the PCIe links at 100 MHz (before serialization encoding), and USB at 480 MHz or 5 GHz depending on the version.&lt;&#x2F;p&gt;
&lt;p&gt;Each of these frequencies defines a clock domain. Within a domain, all logic runs synchronously -- every flip-flop sees the same clock edge at the same time. But when data crosses from one domain to another, there is a problem: the two clocks are not synchronized. A signal that is stable in one domain might be changing at the exact moment the other domain tries to read it.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Clock domain crossing&lt;&#x2F;strong&gt;
The boundary where data passes between two parts of a system running at different clock frequencies. Special synchronization circuits are needed at these boundaries to prevent data corruption. Getting clock domain crossings wrong is one of the most common sources of hardware bugs.
&lt;&#x2F;div&gt;
&lt;p&gt;Engineers solve this with synchronizer circuits -- typically a pair of flip-flops in the receiving domain that sample the incoming signal twice, giving it time to settle before the receiving logic uses it. This adds a small delay (usually two clock cycles of the receiving domain) but prevents data corruption.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dynamic-frequency-scaling&quot;&gt;Dynamic Frequency Scaling&lt;&#x2F;h2&gt;
&lt;p&gt;Modern processors do not run at a fixed clock speed. They adjust their frequency continuously based on workload and temperature. This is called dynamic frequency scaling, or DVFS (Dynamic Voltage and Frequency Scaling).&lt;&#x2F;p&gt;
&lt;p&gt;When the CPU is idle, it drops to a low frequency -- sometimes as low as 400 MHz -- to save power. When a demanding workload arrives, it ramps up to its maximum rated frequency. If it gets too hot, it throttles back down to prevent damage.&lt;&#x2F;p&gt;
&lt;p&gt;The operating system participates in this process. The kernel&#x27;s cpufreq subsystem communicates with the CPU&#x27;s power management hardware to set frequency targets. The &quot;performance&quot; governor locks the CPU at maximum speed. The &quot;powersave&quot; governor keeps it at minimum. The &quot;schedutil&quot; governor (default on modern Linux) adjusts frequency based on actual scheduler utilization data.&lt;&#x2F;p&gt;
&lt;p&gt;This is relevant to boot because during kernel initialization, the CPU typically runs at its base frequency. Turbo boost and dynamic scaling are configured later, once the kernel has set up the cpufreq subsystem and loaded the appropriate driver. The boot messages you see often include lines like:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;[    1.234567] cpufreq: Using governor schedutil
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That marks the moment the kernel takes control of the processor&#x27;s clock speed.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
A computer&#x27;s timing system starts with a single quartz crystal and scales up through PLLs and clock trees to deliver precise timing to billions of transistors. Clock speed matters, but instructions per cycle matters just as much. Modern CPUs dynamically adjust their frequency thousands of times per second based on workload and thermal conditions.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;why-this-matters-for-boot&quot;&gt;Why This Matters for Boot&lt;&#x2F;h2&gt;
&lt;p&gt;Every step in the boot process we have covered so far -- fetching instructions from the BIOS, reading sectors from disk, decompressing the kernel, running &lt;code&gt;start_kernel()&lt;&#x2F;code&gt; -- happens on the clock&#x27;s rising edge. Every memory access, every comparison, every branch decision advances one tick at a time.&lt;&#x2F;p&gt;
&lt;p&gt;When you see a boot time of 3.5 seconds, that represents roughly 14 billion clock ticks at 4 GHz. Each tick is a single step. That the kernel can go from a blank slate to a running operating system in 14 billion steps -- setting up memory, interrupts, scheduling, drivers, filesystems, and launching userspace -- is a testament to both the speed of modern hardware and the efficiency of the kernel&#x27;s initialization code.&lt;&#x2F;p&gt;
&lt;p&gt;The clock never stops. It never pauses. From the moment the crystal starts vibrating until the moment you pull the power cord, it ticks on, driving every computation the machine will ever perform.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;12-device-drivers&#x2F;&quot;&gt;Device Drivers&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Kernel Init</title>
        <published>2025-01-14T00:00:00+00:00</published>
        <updated>2025-01-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/11-kernel-init/"/>
        <id>https://t34ch.tech/coldboot/articles/11-kernel-init/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/11-kernel-init/">&lt;p&gt;The bootloader has done its job. It found the kernel image on disk, loaded it into memory, decompressed it, and jumped to its entry point. The processor is now executing kernel code. But the kernel is not yet an operating system. It is a large program that has just started running on bare hardware with almost nothing set up.&lt;&#x2F;p&gt;
&lt;p&gt;What happens next is a precisely ordered sequence of initialization steps. Each step builds on the one before it. Skip one, get the order wrong, and the machine hangs or panics. This article follows the kernel from its first instruction to the moment it launches the first userspace process.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-entry-point&quot;&gt;The Entry Point&lt;&#x2F;h2&gt;
&lt;p&gt;On x86-64 Linux, the kernel&#x27;s journey begins in architecture-specific assembly code. This code was written by hand, not generated by a compiler, because the machine is not yet in a state where compiled C code can run safely. There is no stack. The memory management unit may not be configured. Interrupts are disabled.&lt;&#x2F;p&gt;
&lt;p&gt;The assembly stub does the minimum work needed to get into C territory: it sets up a temporary stack, configures the page tables for the kernel&#x27;s own memory, enables the memory management unit, and then calls the C function &lt;code&gt;start_kernel()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: start_kernel()&lt;&#x2F;strong&gt;
The C function where Linux kernel initialization truly begins. Located in init&#x2F;main.c in the kernel source tree, it is the single entry point for all of the kernel&#x27;s high-level setup. Everything before it is architecture-specific assembly. Everything after it is portable C.
&lt;&#x2F;div&gt;
&lt;p&gt;Think of it like building a house. The assembly stub pours the foundation and frames the first wall. &lt;code&gt;start_kernel()&lt;&#x2F;code&gt; is the general contractor who arrives and begins coordinating every trade -- electricians, plumbers, roofers -- in the right order.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-start-kernel-does&quot;&gt;What start_kernel() Does&lt;&#x2F;h2&gt;
&lt;p&gt;The function is roughly 100 lines of sequential function calls. Each call initializes one kernel subsystem. The order matters because later subsystems depend on earlier ones. Here is a simplified view of the sequence:&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 11a -- start_kernel() initialization sequence&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 520&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;520&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Timeline arrow --&gt;
  &lt;line x1=&quot;80&quot; y1=&quot;40&quot; x2=&quot;80&quot; y2=&quot;490&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;80,495 75,485 85,485&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;text x=&quot;75&quot; y=&quot;510&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;TIME&lt;&#x2F;text&gt;
  &lt;!-- Step 1 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;30&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;48&quot; r=&quot;5&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;53&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;lock_kernel() -- take the Big Kernel Lock&lt;&#x2F;text&gt;
  &lt;!-- Step 2 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;80&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;98&quot; r=&quot;5&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;103&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;setup_arch() -- CPU, memory map, platform&lt;&#x2F;text&gt;
  &lt;!-- Step 3 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;130&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;148&quot; r=&quot;5&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;153&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;trap_init() -- exception handlers&lt;&#x2F;text&gt;
  &lt;!-- Step 4 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;180&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;198&quot; r=&quot;5&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;203&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;mm_init() -- memory management&lt;&#x2F;text&gt;
  &lt;!-- Step 5 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;230&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;248&quot; r=&quot;5&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;253&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;sched_init() -- process scheduler&lt;&#x2F;text&gt;
  &lt;!-- Step 6 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;280&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;298&quot; r=&quot;5&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;303&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;init_IRQ() -- interrupt controllers&lt;&#x2F;text&gt;
  &lt;!-- Step 7 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;330&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;348&quot; r=&quot;5&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;353&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;time_init() -- system clock&lt;&#x2F;text&gt;
  &lt;!-- Step 8 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;380&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;398&quot; r=&quot;5&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;403&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;console_init() -- early printk output&lt;&#x2F;text&gt;
  &lt;!-- Step 9 --&gt;
  &lt;rect x=&quot;110&quot; y=&quot;430&quot; width=&quot;420&quot; height=&quot;36&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;circle cx=&quot;80&quot; cy=&quot;448&quot; r=&quot;5&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;320&quot; y=&quot;453&quot; fill=&quot;#C0392B&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;rest_init() -- spawn PID 1, idle loop&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A simplified view of the major calls inside start_kernel(). Each step depends on the ones above it. The kernel must complete them in order.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Let us walk through the most important ones.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setting-up-the-architecture&quot;&gt;Setting Up the Architecture&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;setup_arch()&lt;&#x2F;code&gt; is where the kernel learns what kind of machine it is running on. On x86, this function reads the memory map that the BIOS or UEFI firmware left behind, identifies the CPU model and its capabilities, and configures architecture-specific features.&lt;&#x2F;p&gt;
&lt;p&gt;The memory map is critical. It tells the kernel which regions of physical memory are usable RAM, which are reserved by firmware, and which are mapped to hardware devices. Without this map, the kernel cannot allocate memory safely -- it might overwrite firmware data or try to use an address that corresponds to a device register instead of RAM.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;setup_arch()&lt;&#x2F;code&gt; also detects how many CPU cores are present and prepares data structures for each one. On a multi-core machine, only one core -- the bootstrap processor -- runs &lt;code&gt;start_kernel()&lt;&#x2F;code&gt;. The other cores sit idle until the kernel explicitly wakes them later.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Bootstrap Processor (BSP)&lt;&#x2F;strong&gt;
The single CPU core that the hardware selects to run the boot sequence. All other cores are Application Processors (APs). The BSP performs all kernel initialization and then wakes the APs one by one.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;memory-management&quot;&gt;Memory Management&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;mm_init()&lt;&#x2F;code&gt; builds the kernel&#x27;s memory management system. Before this call, the kernel uses a simple boot-time allocator that hands out memory in chunks and never reclaims it. That works for early setup, but it is far too wasteful for a running system.&lt;&#x2F;p&gt;
&lt;p&gt;The full memory manager divides physical RAM into fixed-size pages, typically 4,096 bytes each. It tracks which pages are free and which are in use. It sets up the page tables that let the CPU translate virtual addresses -- the addresses that programs see -- into physical addresses where data actually lives in the RAM chips.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 11b -- Virtual to physical address translation&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Virtual address space --&gt;
&lt;p&gt;&lt;text x=&quot;130&quot; y=&quot;30&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;VIRTUAL&lt;&#x2F;text&gt;
&lt;rect x=&quot;40&quot; y=&quot;40&quot; width=&quot;180&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
&lt;text x=&quot;130&quot; y=&quot;65&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Process A: 0x4000&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;40&quot; y=&quot;90&quot; width=&quot;180&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;115&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Process B: 0x4000&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;140&quot; width=&quot;180&quot; height=&quot;40&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;165&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Kernel: 0xFFFF8000&lt;&#x2F;text&gt;
  &lt;!-- Page tables box --&gt;
  &lt;rect x=&quot;240&quot; y=&quot;80&quot; width=&quot;100&quot; height=&quot;60&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;105&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;PAGE&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;120&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;TABLES&lt;&#x2F;text&gt;
  &lt;!-- Physical RAM --&gt;
&lt;p&gt;&lt;text x=&quot;460&quot; y=&quot;30&quot; fill=&quot;#39D353&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;PHYSICAL RAM&lt;&#x2F;text&gt;
&lt;rect x=&quot;380&quot; y=&quot;40&quot; width=&quot;160&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
&lt;text x=&quot;460&quot; y=&quot;60&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x00000 firmware&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;380&quot; y=&quot;75&quot; width=&quot;160&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;460&quot; y=&quot;95&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x12000 page A&lt;&#x2F;text&gt;
  &lt;rect x=&quot;380&quot; y=&quot;110&quot; width=&quot;160&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;460&quot; y=&quot;130&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x1F000 free&lt;&#x2F;text&gt;
  &lt;rect x=&quot;380&quot; y=&quot;145&quot; width=&quot;160&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;460&quot; y=&quot;165&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x34000 page B&lt;&#x2F;text&gt;
  &lt;rect x=&quot;380&quot; y=&quot;180&quot; width=&quot;160&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;460&quot; y=&quot;200&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x80000 kernel&lt;&#x2F;text&gt;
  &lt;!-- Arrows --&gt;
  &lt;line x1=&quot;220&quot; y1=&quot;60&quot; x2=&quot;240&quot; y2=&quot;100&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow11b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;220&quot; y1=&quot;110&quot; x2=&quot;240&quot; y2=&quot;110&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow11b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;220&quot; y1=&quot;160&quot; x2=&quot;240&quot; y2=&quot;118&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow11b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;96&quot; x2=&quot;380&quot; y2=&quot;90&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow11b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;110&quot; x2=&quot;380&quot; y2=&quot;160&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow11b)&quot;&#x2F;&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;118&quot; x2=&quot;380&quot; y2=&quot;195&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow11b)&quot;&#x2F;&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrow11b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;polygon points=&quot;0,0 8,3 0,6&quot; fill=&quot;#F5F5F5&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
  &lt;!-- Caption area --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;240&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Both processes use address 0x4000,&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;256&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;but page tables map them to different&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;272&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;physical locations. Each process sees&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;288&quot; fill=&quot;#EEECE6&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;its own private address space.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Virtual memory gives each process the illusion of having its own private address space. The page tables translate virtual addresses to physical RAM locations. Two processes can use the same virtual address without conflicting.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;This translation mechanism is fundamental to everything the operating system does. It lets multiple programs run at the same time without stepping on each other&#x27;s memory. It lets the kernel protect its own data from buggy or malicious programs. It enables features like swap, memory-mapped files, and copy-on-write.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The memory management subsystem is one of the first things the kernel sets up because almost everything else depends on it. Without the ability to allocate and track pages, the kernel cannot create processes, load drivers, or mount filesystems.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-scheduler&quot;&gt;The Scheduler&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;sched_init()&lt;&#x2F;code&gt; creates the process scheduler. A scheduler is the piece of the kernel that decides which program runs on which CPU core and for how long. At this point, no user programs exist, but the scheduler infrastructure must be in place before the kernel can create any processes -- including the very first one.&lt;&#x2F;p&gt;
&lt;p&gt;The scheduler maintains a run queue for each CPU core. A run queue is a list of processes that are ready to execute. When a core finishes its current time slice or a process blocks waiting for I&#x2F;O, the scheduler picks the next process from the queue.&lt;&#x2F;p&gt;
&lt;p&gt;Linux uses the Completely Fair Scheduler (CFS) by default. The name reflects its design goal: give every process a fair share of CPU time proportional to its priority. CFS tracks how much CPU time each process has consumed using a virtual runtime counter. The process with the lowest virtual runtime runs next.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Scheduler&lt;&#x2F;strong&gt;
The kernel subsystem that decides which process runs on each CPU core. It multiplexes many processes onto a limited number of cores, switching between them fast enough to create the illusion of simultaneous execution.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;interrupts&quot;&gt;Interrupts&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;init_IRQ()&lt;&#x2F;code&gt; sets up the interrupt system. An interrupt is a signal from hardware -- or from software -- that tells the CPU to stop what it is doing and handle an event. When you press a key, the keyboard controller sends an interrupt. When a network packet arrives, the network card sends one. When a timer fires, the timer hardware sends one.&lt;&#x2F;p&gt;
&lt;p&gt;Each interrupt has a number. The kernel installs a handler function for each number -- a piece of code that knows how to respond to that specific event. When interrupt number 42 fires, the CPU looks up handler 42 and runs it.&lt;&#x2F;p&gt;
&lt;p&gt;Before &lt;code&gt;init_IRQ()&lt;&#x2F;code&gt;, the interrupt controllers are not configured and any hardware interrupt would either be ignored or crash the machine. After this call, the kernel can respond to hardware events.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-console&quot;&gt;The Console&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;console_init()&lt;&#x2F;code&gt; sets up early text output. Every line of boot text you see scrolling by -- the &lt;code&gt;[    0.000000]&lt;&#x2F;code&gt; timestamped messages -- comes through this subsystem. The kernel needs a way to tell you what it is doing (and what went wrong) before the full display driver is loaded.&lt;&#x2F;p&gt;
&lt;p&gt;The early console typically talks directly to the VGA text buffer at a fixed memory address, or to a serial port. It is crude but reliable. Later in the boot process, a full framebuffer console or graphical display takes over.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rest-init-and-the-birth-of-pid-1&quot;&gt;rest_init() and the Birth of PID 1&lt;&#x2F;h2&gt;
&lt;p&gt;After all subsystems are initialized, &lt;code&gt;start_kernel()&lt;&#x2F;code&gt; calls &lt;code&gt;rest_init()&lt;&#x2F;code&gt;. This function does three critical things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;It creates a kernel thread called &lt;code&gt;kthreadd&lt;&#x2F;code&gt; (PID 2), which will be the parent of all future kernel threads.&lt;&#x2F;li&gt;
&lt;li&gt;It creates the &lt;code&gt;init&lt;&#x2F;code&gt; process (PID 1), which will become the first userspace process.&lt;&#x2F;li&gt;
&lt;li&gt;It turns the bootstrap code path into the idle thread (PID 0) -- the thread that runs when there is nothing else to do.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 11c -- The first three processes&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 260&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;260&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- PID 0 --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;20&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;42&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;PID 0&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;58&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;idle (swapper)&lt;&#x2F;text&gt;
  &lt;!-- Lines down --&gt;
  &lt;line x1=&quot;230&quot; y1=&quot;70&quot; x2=&quot;150&quot; y2=&quot;110&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;line x1=&quot;350&quot; y1=&quot;70&quot; x2=&quot;430&quot; y2=&quot;110&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- PID 1 --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;110&quot; width=&quot;180&quot; height=&quot;50&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;150&quot; y=&quot;132&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;PID 1&lt;&#x2F;text&gt;
  &lt;text x=&quot;150&quot; y=&quot;148&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;init (userspace)&lt;&#x2F;text&gt;
  &lt;!-- PID 2 --&gt;
  &lt;rect x=&quot;340&quot; y=&quot;110&quot; width=&quot;180&quot; height=&quot;50&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;132&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;PID 2&lt;&#x2F;text&gt;
  &lt;text x=&quot;430&quot; y=&quot;148&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;kthreadd (kernel)&lt;&#x2F;text&gt;
  &lt;!-- Children of PID 1 --&gt;
  &lt;line x1=&quot;100&quot; y1=&quot;160&quot; x2=&quot;65&quot; y2=&quot;190&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;160&quot; x2=&quot;150&quot; y2=&quot;190&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;line x1=&quot;200&quot; y1=&quot;160&quot; x2=&quot;235&quot; y2=&quot;190&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;rect x=&quot;20&quot; y=&quot;190&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;65&quot; y=&quot;210&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;services&lt;&#x2F;text&gt;
  &lt;rect x=&quot;120&quot; y=&quot;190&quot; width=&quot;60&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;150&quot; y=&quot;210&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;login&lt;&#x2F;text&gt;
  &lt;rect x=&quot;190&quot; y=&quot;190&quot; width=&quot;70&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;225&quot; y=&quot;210&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;shells&lt;&#x2F;text&gt;
  &lt;!-- Children of PID 2 --&gt;
  &lt;line x1=&quot;395&quot; y1=&quot;160&quot; x2=&quot;355&quot; y2=&quot;190&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;line x1=&quot;430&quot; y1=&quot;160&quot; x2=&quot;430&quot; y2=&quot;190&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;line x1=&quot;465&quot; y1=&quot;160&quot; x2=&quot;505&quot; y2=&quot;190&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;rect x=&quot;310&quot; y=&quot;190&quot; width=&quot;90&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;355&quot; y=&quot;210&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;kworker&lt;&#x2F;text&gt;
  &lt;rect x=&quot;405&quot; y=&quot;190&quot; width=&quot;50&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;210&quot; fill=&quot;#EEECE6&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;softirq&lt;&#x2F;text&gt;
  &lt;rect x=&quot;460&quot; y=&quot;190&quot; width=&quot;95&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;508&quot; y=&quot;210&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;migration&lt;&#x2F;text&gt;
  &lt;!-- Legend --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;248&quot; fill=&quot;#EEECE6&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;PID 0 creates both PID 1 and PID 2. All userspace from 1, kernel threads from 2.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The kernel&#x27;s first three processes form the root of the entire process tree. PID 1 (init) is the ancestor of every userspace program. PID 2 (kthreadd) parents all kernel worker threads.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;PID 1 is special. If it dies, the kernel panics. It is the root of the entire userspace process tree. Every daemon, every shell, every application is ultimately a descendant of PID 1. We will explore PID 1 in detail in a later article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-kernel-command-line&quot;&gt;The Kernel Command Line&lt;&#x2F;h2&gt;
&lt;p&gt;Throughout initialization, the kernel reads parameters from its command line -- a string passed by the bootloader. You can see your system&#x27;s kernel command line by reading &lt;code&gt;&#x2F;proc&#x2F;cmdline&lt;&#x2F;code&gt;. Typical entries include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;root=&#x2F;dev&#x2F;sda2&lt;&#x2F;code&gt; -- which partition holds the root filesystem&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ro&lt;&#x2F;code&gt; -- mount root as read-only initially&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;quiet&lt;&#x2F;code&gt; -- suppress most boot messages&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;init=&#x2F;sbin&#x2F;init&lt;&#x2F;code&gt; -- which program to run as PID 1&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These parameters influence how nearly every subsystem initializes. The &lt;code&gt;root=&lt;&#x2F;code&gt; parameter, for example, determines which block device the kernel will try to mount as the root filesystem. The &lt;code&gt;init=&lt;&#x2F;code&gt; parameter lets you override the default PID 1 binary, which is useful for rescue situations.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The kernel command line is the bridge between the bootloader and the kernel. It carries configuration that the kernel cannot determine on its own, such as which disk partition holds the root filesystem or how verbose the boot messages should be.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-kernel-log&quot;&gt;The Kernel Log&lt;&#x2F;h2&gt;
&lt;p&gt;As each subsystem initializes, it writes messages to the kernel log buffer -- a ring buffer in memory. These are the &lt;code&gt;dmesg&lt;&#x2F;code&gt; messages you can read after the system is running. Each message is timestamped relative to the start of boot.&lt;&#x2F;p&gt;
&lt;p&gt;The early messages tell you exactly what the kernel found and configured:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;[    0.000000] Linux version 6.8.0 ...
[    0.000000] Command line: root=&#x2F;dev&#x2F;sda2 ro quiet
[    0.004523] Memory: 16384MB available
[    0.012847] CPU: 8 cores detected
[    0.089234] Scheduler: CFS initialized
[    0.102456] Interrupt controller: APIC configured
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Reading &lt;code&gt;dmesg&lt;&#x2F;code&gt; is one of the most useful debugging tools available. If a piece of hardware does not work, the answer is almost always in these messages.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-kernel-to-userspace&quot;&gt;From Kernel to Userspace&lt;&#x2F;h2&gt;
&lt;p&gt;Once &lt;code&gt;rest_init()&lt;&#x2F;code&gt; spawns PID 1, the kernel&#x27;s direct initialization work is largely done. PID 1 -- whether it is the traditional &lt;code&gt;init&lt;&#x2F;code&gt;, &lt;code&gt;systemd&lt;&#x2F;code&gt;, or another init system -- takes over the job of starting services, mounting filesystems, and bringing the system to a usable state.&lt;&#x2F;p&gt;
&lt;p&gt;But the kernel does not go away. It continues running underneath everything, handling interrupts, managing memory, scheduling processes, and mediating every interaction between software and hardware. The kernel is not a program that runs and exits. It is the permanent foundation on which everything else stands.&lt;&#x2F;p&gt;
&lt;p&gt;The transition from kernel initialization to userspace is the moment the computer stops being a machine running setup code and becomes an operating system. The next articles explore the subsystems that make this possible -- starting with the clock signal that times every operation.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;11b-the-clock-signal&#x2F;&quot;&gt;The Clock Signal&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Decompressing and Handing Off</title>
        <published>2025-01-13T00:00:00+00:00</published>
        <updated>2025-01-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/10b-decompressing-and-handing-off/"/>
        <id>https://t34ch.tech/coldboot/articles/10b-decompressing-and-handing-off/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/10b-decompressing-and-handing-off/">&lt;p&gt;GRUB has loaded the kernel image into memory and jumped to its entry point. But the code now running is not the Linux kernel. It is the decompression stub -- a small, self-contained program embedded at the front of the bzImage. Its job is to decompress the actual kernel, move it to its final address, and jump to it.&lt;&#x2F;p&gt;
&lt;p&gt;Between the bootloader&#x27;s jump and the kernel&#x27;s first real instruction, two major transitions happen. First, the compressed kernel must be extracted into a working executable. Second, the CPU must switch from the constrained 16-bit real mode it has been running in since power-on to the full 32-bit (or 64-bit) protected mode that the kernel requires. These two operations are deeply intertwined.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-the-kernel-is-compressed&quot;&gt;Why the Kernel Is Compressed&lt;&#x2F;h2&gt;
&lt;p&gt;A modern Linux kernel, compiled with a typical desktop or server configuration, produces an uncompressed &lt;code&gt;vmlinux&lt;&#x2F;code&gt; binary of 30 to 80 megabytes. That is a lot of data to load from disk during boot. Disk reads are slow -- even on an NVMe drive, reading 60 MB takes noticeably longer than reading 12 MB.&lt;&#x2F;p&gt;
&lt;p&gt;Compression shrinks the kernel to roughly one-fifth its original size. The trade-off is CPU time: the decompressor must run after loading to recover the original data. But CPUs are fast and disk I&#x2F;O is relatively slow, so decompressing in memory is almost always faster than loading the uncompressed image from disk. The net boot time is shorter with compression.&lt;&#x2F;p&gt;
&lt;p&gt;The Linux kernel build system supports several compression algorithms:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;gzip&lt;&#x2F;strong&gt; -- the original default. Good compression ratio, moderate speed.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LZ4&lt;&#x2F;strong&gt; -- faster decompression, slightly larger output.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LZMA &#x2F; XZ&lt;&#x2F;strong&gt; -- higher compression ratio, slower decompression.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Zstandard (zstd)&lt;&#x2F;strong&gt; -- good balance of ratio and speed. Increasingly the default on modern distributions.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The choice is made at kernel compile time (&lt;code&gt;CONFIG_KERNEL_GZIP&lt;&#x2F;code&gt;, &lt;code&gt;CONFIG_KERNEL_LZ4&lt;&#x2F;code&gt;, etc.). The decompression stub is built to match: it contains exactly one decompressor, for whichever algorithm was selected.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Decompression stub&lt;&#x2F;strong&gt;
A small program concatenated to the front of the compressed kernel data inside the bzImage. It contains the decompression algorithm (gzip, LZ4, zstd, etc.), memory setup code, and the logic to place the decompressed kernel at its final address. It runs once and then jumps to the real kernel, never to be used again.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-first-instructions-real-mode-setup&quot;&gt;The First Instructions: Real-Mode Setup&lt;&#x2F;h2&gt;
&lt;p&gt;When GRUB jumps to the kernel&#x27;s entry point, execution begins in the real-mode setup code -- the part of the bzImage that GRUB loaded to low memory (around 0x10000). This code runs with the CPU still in 16-bit real mode. It performs a series of preparedness checks and hardware queries before the transition to protected mode.&lt;&#x2F;p&gt;
&lt;p&gt;The real-mode setup code does the following:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Normalizes the CPU state.&lt;&#x2F;strong&gt; Sets segment registers to known values, clears the direction flag, and establishes a stack.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Queries the BIOS for hardware information.&lt;&#x2F;strong&gt; This is the last chance to use BIOS services, because they only work in real mode. The code calls INT 0x15 to get the system memory map (the E820 map), INT 0x10 to query video modes, and other interrupts to detect hardware features. All results are stored in the boot parameters structure where the kernel will read them later.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enables the A20 line.&lt;&#x2F;strong&gt; On the original IBM PC, address line 20 was disabled to maintain compatibility with 8086 programs that relied on address wraparound. Enabling the A20 line allows the CPU to address memory above 1 MB. Without it, protected mode cannot access the full address space. The A20 enabling code tries several methods (keyboard controller, Fast A20 via port 0x92, BIOS INT 0x15) because different hardware requires different approaches.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Prepares for the mode switch.&lt;&#x2F;strong&gt; The code loads a temporary Global Descriptor Table (GDT) and Interrupt Descriptor Table (IDT) -- the data structures that the CPU requires before it can enter protected mode.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: A20 line&lt;&#x2F;strong&gt;
The 21st address line (bit 20) of the CPU&#x27;s address bus. On the original 8086, only 20 address lines existed, and addresses above 1 MB wrapped around to zero. The IBM AT added the A20 line but kept it disabled by default for backward compatibility. Every boot sequence must explicitly enable it before the CPU can access memory above 1 MB.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 10b-1 -- Real-mode setup sequence&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Timeline --&gt;
  &lt;line x1=&quot;70&quot; y1=&quot;40&quot; x2=&quot;70&quot; y2=&quot;270&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- Step 1 --&gt;
  &lt;circle cx=&quot;70&quot; cy=&quot;55&quot; r=&quot;5&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;rect x=&quot;100&quot; y=&quot;40&quot; width=&quot;440&quot; height=&quot;30&quot; fill=&quot;rgba(255,215,0,0.1)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;115&quot; y=&quot;60&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot;&gt;Normalize CPU state: segments, stack, flags&lt;&#x2F;text&gt;
  &lt;!-- Step 2 --&gt;
  &lt;circle cx=&quot;70&quot; cy=&quot;100&quot; r=&quot;5&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;rect x=&quot;100&quot; y=&quot;85&quot; width=&quot;440&quot; height=&quot;30&quot; fill=&quot;rgba(0,191,255,0.1)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;115&quot; y=&quot;105&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;BIOS queries: E820 memory map, video modes, APM&lt;&#x2F;text&gt;
  &lt;!-- Step 3 --&gt;
  &lt;circle cx=&quot;70&quot; cy=&quot;145&quot; r=&quot;5&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
  &lt;rect x=&quot;100&quot; y=&quot;130&quot; width=&quot;440&quot; height=&quot;30&quot; fill=&quot;rgba(255,102,0,0.1)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;115&quot; y=&quot;150&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot;&gt;Enable A20 line (keyboard controller &#x2F; Fast A20 &#x2F; BIOS)&lt;&#x2F;text&gt;
  &lt;!-- Step 4 --&gt;
  &lt;circle cx=&quot;70&quot; cy=&quot;190&quot; r=&quot;5&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;rect x=&quot;100&quot; y=&quot;175&quot; width=&quot;440&quot; height=&quot;30&quot; fill=&quot;rgba(57,211,83,0.1)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;115&quot; y=&quot;195&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;Load temporary GDT and IDT&lt;&#x2F;text&gt;
  &lt;!-- Step 5 --&gt;
  &lt;circle cx=&quot;70&quot; cy=&quot;235&quot; r=&quot;5&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;rect x=&quot;100&quot; y=&quot;220&quot; width=&quot;440&quot; height=&quot;30&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;115&quot; y=&quot;240&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot;&gt;Set CR0.PE = 1  --&gt;  ENTER PROTECTED MODE&lt;&#x2F;text&gt;
  &lt;!-- Mode label --&gt;
&lt;p&gt;&lt;text x=&quot;40&quot; y=&quot;130&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot; transform=&quot;rotate(-90, 40, 130)&quot;&gt;16-bit Real Mode&lt;&#x2F;text&gt;
&lt;line x1=&quot;55&quot; y1=&quot;40&quot; x2=&quot;55&quot; y2=&quot;210&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;40&quot; y=&quot;260&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot; transform=&quot;rotate(-90, 40, 260)&quot;&gt;32-bit&lt;&#x2F;text&gt;
&lt;line x1=&quot;55&quot; y1=&quot;215&quot; x2=&quot;55&quot; y2=&quot;270&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
  &lt;!-- Annotation --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;285&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Last chance for BIOS interrupts is step 2. After step 5, BIOS is gone.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The real-mode setup code runs a sequence of preparation steps, culminating in the switch to protected mode. BIOS services are only available during the first two steps.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-mode-switch&quot;&gt;The Mode Switch&lt;&#x2F;h2&gt;
&lt;p&gt;The transition from real mode to protected mode is one of the most important moments in the boot process. In real mode, the CPU acts like a fast 1981 processor: 16-bit operations, 1 MB address space, no memory protection. In protected mode, the CPU gains 32-bit operations, a 4 GB address space, memory segmentation with privilege levels, and the ability to run the kind of code that a modern operating system requires.&lt;&#x2F;p&gt;
&lt;p&gt;The switch itself is a single instruction: setting bit 0 (the PE bit, for Protection Enable) in the CR0 control register. But that one instruction only works if the ground has been prepared. The GDT must be loaded. The A20 line must be enabled. Interrupts must be disabled (the real-mode interrupt handlers would crash if called in protected mode).&lt;&#x2F;p&gt;
&lt;p&gt;The sequence looks like this in pseudocode:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;cli                     ; disable interrupts
lgdt [gdt_pointer]      ; load the Global Descriptor Table
mov eax, cr0            ; read CR0
or  eax, 1              ; set PE bit
mov cr0, eax            ; write CR0 -- NOW IN PROTECTED MODE
jmp 0x10:protected_entry ; far jump to reload CS with a 32-bit selector
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The far jump immediately after setting CR0 is essential. It flushes the CPU&#x27;s instruction pipeline and loads the code segment register (CS) with a selector that points to a 32-bit code segment in the GDT. Without this jump, the CPU would continue fetching instructions using the old 16-bit CS value, and the next instruction would be decoded incorrectly.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Global Descriptor Table (GDT)&lt;&#x2F;strong&gt;
A table in memory that defines memory segments for the CPU in protected mode. Each entry describes a segment&#x27;s base address, size, type (code or data), and privilege level. The CPU consults the GDT on every memory access to enforce segment boundaries and permissions. The kernel will replace the boot GDT with its own shortly after starting.
&lt;&#x2F;div&gt;
&lt;div class=&quot;remember&quot;&gt;
The switch from real mode to protected mode is a one-way door during boot. Once the PE bit is set in CR0, BIOS interrupts stop working, the address space expands from 1 MB to 4 GB, and the CPU enforces segment-based memory protection. The far jump immediately after the switch is mandatory to flush the instruction pipeline and load a valid 32-bit code segment.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;on-64-bit-systems-the-long-mode-jump&quot;&gt;On 64-Bit Systems: The Long Mode Jump&lt;&#x2F;h2&gt;
&lt;p&gt;Modern x86-64 systems take the mode switching further. The kernel needs 64-bit long mode to access the full address space and use 64-bit registers. On these systems, the decompression stub typically transitions through protected mode and then into long mode before decompressing.&lt;&#x2F;p&gt;
&lt;p&gt;The transition to long mode requires additional steps beyond protected mode:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set up page tables.&lt;&#x2F;strong&gt; Long mode requires paging to be enabled. The stub creates a minimal identity-mapped page table -- a page table where virtual addresses equal physical addresses. This is temporary; the kernel will build its own page tables later.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enable PAE.&lt;&#x2F;strong&gt; Physical Address Extension (bit 5 of CR4) must be set. Long mode requires it.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set the LME bit.&lt;&#x2F;strong&gt; The Long Mode Enable bit in the EFER (Extended Feature Enable Register) MSR signals the CPU to prepare for 64-bit operation.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enable paging.&lt;&#x2F;strong&gt; Setting the PG bit (bit 31) in CR0, with LME already set, activates long mode.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Far jump to 64-bit code.&lt;&#x2F;strong&gt; Like the real-to-protected switch, a far jump reloads CS with a 64-bit code segment selector.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;After this sequence, the CPU is in 64-bit mode with identity-mapped paging, and the decompressor can use the full address space.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 10b-2 -- CPU mode transitions during boot&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 180&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;180&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Real mode --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;60&quot; width=&quot;130&quot; height=&quot;60&quot; fill=&quot;rgba(192,57,43,0.15)&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;85&quot; y=&quot;82&quot; fill=&quot;#C0392B&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Real Mode&lt;&#x2F;text&gt;
  &lt;text x=&quot;85&quot; y=&quot;98&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;16-bit, 1 MB&lt;&#x2F;text&gt;
  &lt;text x=&quot;85&quot; y=&quot;112&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;BIOS available&lt;&#x2F;text&gt;
  &lt;!-- Arrow --&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;90&quot; x2=&quot;195&quot; y2=&quot;90&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;195,85 205,90 195,95&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;text x=&quot;177&quot; y=&quot;78&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;CR0.PE=1&lt;&#x2F;text&gt;
  &lt;!-- Protected mode --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;60&quot; width=&quot;130&quot; height=&quot;60&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;275&quot; y=&quot;82&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Protected Mode&lt;&#x2F;text&gt;
  &lt;text x=&quot;275&quot; y=&quot;98&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;32-bit, 4 GB&lt;&#x2F;text&gt;
  &lt;text x=&quot;275&quot; y=&quot;112&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;segmentation&lt;&#x2F;text&gt;
  &lt;!-- Arrow --&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;90&quot; x2=&quot;385&quot; y2=&quot;90&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;385,85 395,90 385,95&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;text x=&quot;362&quot; y=&quot;78&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;CR0.PG=1&lt;&#x2F;text&gt;
  &lt;text x=&quot;362&quot; y=&quot;68&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;+LME+PAE&lt;&#x2F;text&gt;
  &lt;!-- Long mode --&gt;
  &lt;rect x=&quot;400&quot; y=&quot;60&quot; width=&quot;150&quot; height=&quot;60&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;475&quot; y=&quot;82&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Long Mode&lt;&#x2F;text&gt;
  &lt;text x=&quot;475&quot; y=&quot;98&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;64-bit, 256 TB&lt;&#x2F;text&gt;
  &lt;text x=&quot;475&quot; y=&quot;112&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;paging required&lt;&#x2F;text&gt;
  &lt;!-- Timeline labels --&gt;
&lt;p&gt;&lt;text x=&quot;85&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;BIOS &#x2F; GRUB&lt;&#x2F;text&gt;
&lt;text x=&quot;275&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;transient&lt;&#x2F;text&gt;
&lt;text x=&quot;475&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;kernel runs here&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;line x1=&quot;20&quot; y1=&quot;155&quot; x2=&quot;560&quot; y2=&quot;155&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;172&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Each transition requires a far jump to flush the instruction pipeline&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The CPU transitions through three modes during boot. Real mode is used for BIOS interaction, protected mode is a stepping stone, and long mode is where the kernel runs on 64-bit systems.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-decompression&quot;&gt;The Decompression&lt;&#x2F;h2&gt;
&lt;p&gt;With the CPU in the correct mode, the decompression stub can do its primary job: decompress the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;The stub knows the exact location and size of the compressed data because these values were embedded in the image at build time. The compressed kernel payload sits immediately after the stub code in the bzImage. The stub also knows the expected size of the decompressed output.&lt;&#x2F;p&gt;
&lt;p&gt;The process is straightforward in concept:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Determine the output address. The stub decompresses the kernel to a location that does not overlap with the compressed data or the stub itself. The kernel build system calculates safe addresses at compile time.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Call the decompressor. The stub invokes the appropriate decompression function (gzip&#x27;s &lt;code&gt;inflate&lt;&#x2F;code&gt;, LZ4&#x27;s &lt;code&gt;LZ4_decompress&lt;&#x2F;code&gt;, zstd&#x27;s &lt;code&gt;ZSTD_decompress&lt;&#x2F;code&gt;, etc.). This function reads the compressed data and writes the decompressed kernel to the output address.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Verify the output. Some configurations check a CRC or other integrity value to confirm the decompression produced correct data.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The decompressed output is &lt;code&gt;vmlinux&lt;&#x2F;code&gt; -- the raw kernel ELF binary, stripped of debug symbols. This is the actual Linux kernel: the scheduler, the memory manager, the device driver framework, the system call interface, everything.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 10b-3 -- Decompression and relocation in memory&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Physical Memory During Decompression&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Low memory --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;40&quot; width=&quot;500&quot; height=&quot;30&quot; fill=&quot;rgba(255,215,0,0.1)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;50&quot; y=&quot;59&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;Real-mode setup code + boot params&lt;&#x2F;text&gt;
  &lt;text x=&quot;530&quot; y=&quot;59&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;~0x10000&lt;&#x2F;text&gt;
  &lt;!-- 1MB mark --&gt;
  &lt;line x1=&quot;40&quot; y1=&quot;85&quot; x2=&quot;540&quot; y2=&quot;85&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;text x=&quot;35&quot; y=&quot;82&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;1 MB&lt;&#x2F;text&gt;
  &lt;!-- Compressed kernel + stub (loaded by GRUB) --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;95&quot; width=&quot;500&quot; height=&quot;50&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;115&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Decompression stub + compressed kernel&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;132&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(loaded here by GRUB at 0x100000)&lt;&#x2F;text&gt;
  &lt;!-- Arrow: decompress --&gt;
  &lt;path d=&quot;M 290 145 C 290 165, 290 165, 290 175&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; fill=&quot;none&quot;&#x2F;&gt;
  &lt;polygon points=&quot;285,175 290,185 295,175&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;text x=&quot;340&quot; y=&quot;168&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;decompress&lt;&#x2F;text&gt;
  &lt;!-- Decompressed kernel --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;190&quot; width=&quot;500&quot; height=&quot;55&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;213&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Decompressed kernel (vmlinux)&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;232&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(placed at non-overlapping address, then relocated to final position)&lt;&#x2F;text&gt;
  &lt;!-- Initrd --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;255&quot; width=&quot;500&quot; height=&quot;30&quot; fill=&quot;rgba(255,102,0,0.12)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;274&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;initramfs (loaded by GRUB, untouched)&lt;&#x2F;text&gt;
  &lt;!-- Final jump --&gt;
  &lt;line x1=&quot;540&quot; y1=&quot;217&quot; x2=&quot;555&quot; y2=&quot;217&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;555,212 565,217 555,222&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;555&quot; y=&quot;200&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;jump to&lt;&#x2F;text&gt;
  &lt;text x=&quot;555&quot; y=&quot;240&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;kernel&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The decompression stub extracts the compressed kernel from within the bzImage and places the decompressed vmlinux at a safe address. After relocation to the final address, the stub jumps to the kernel entry point.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;relocation&quot;&gt;Relocation&lt;&#x2F;h2&gt;
&lt;p&gt;The decompressed kernel needs to be at a specific physical address. On x86-64, this is typically 0x1000000 (16 MB) for a relocatable kernel, but the kernel&#x27;s link address (compiled-in start address) determines the expectation.&lt;&#x2F;p&gt;
&lt;p&gt;If the decompressed data is not already at the correct address, the stub copies it there. Modern kernels are often built as position-independent executables (with &lt;code&gt;CONFIG_RELOCATABLE=y&lt;&#x2F;code&gt;), which means they can run at addresses other than their link address. The kernel adjusts its internal references at startup. But the decompression stub still relocates the image to a clean region of memory before jumping.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The decompression stub is a single-use program. It transitions the CPU to the correct mode (protected or long mode), decompresses the kernel payload using the algorithm selected at compile time, places the result at the correct physical address, and jumps to the kernel entry point. After this jump, the decompression stub is never used again -- its memory will be reclaimed by the kernel.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-handoff&quot;&gt;The Handoff&lt;&#x2F;h2&gt;
&lt;p&gt;The final act of the decompression stub is a jump to the kernel&#x27;s entry point -- the &lt;code&gt;startup_64&lt;&#x2F;code&gt; function (on x86-64) or &lt;code&gt;startup_32&lt;&#x2F;code&gt; (on 32-bit systems). At this instant, control passes from boot code to kernel code.&lt;&#x2F;p&gt;
&lt;p&gt;The kernel inherits a specific machine state:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPU mode:&lt;&#x2F;strong&gt; 64-bit long mode (or 32-bit protected mode on older systems), with identity-mapped paging.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Interrupts:&lt;&#x2F;strong&gt; disabled. The kernel will set up its own interrupt handlers before re-enabling them.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Boot parameters:&lt;&#x2F;strong&gt; in a known memory location. These contain the memory map, command line, initrd location, video mode, and other data collected by the real-mode setup code and GRUB.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Memory contents:&lt;&#x2F;strong&gt; the decompressed kernel at its final address, the initramfs at its GRUB-assigned address, and the boot parameters structure in low memory.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The kernel does not depend on GRUB&#x27;s code or data structures. It does not call back to the bootloader. From this point, GRUB might as well not exist. The kernel reads the boot parameters, initializes its own data structures, and begins the process of bringing up a full operating system.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-boot-parameters-zero-page&quot;&gt;The Boot Parameters (Zero Page)&lt;&#x2F;h2&gt;
&lt;p&gt;The boot parameters structure deserves a closer look, because it is the only communication channel between the bootloader world and the kernel world. It occupies the first page (4096 bytes) of the real-mode code segment -- historically called the &quot;zero page&quot; because it starts at offset zero of that segment.&lt;&#x2F;p&gt;
&lt;p&gt;The zero page contains:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The E820 memory map from BIOS (or EFI memory map on UEFI systems).&lt;&#x2F;li&gt;
&lt;li&gt;The kernel command-line pointer and length.&lt;&#x2F;li&gt;
&lt;li&gt;The initrd address and size.&lt;&#x2F;li&gt;
&lt;li&gt;The video mode and framebuffer information.&lt;&#x2F;li&gt;
&lt;li&gt;The number of setup sectors and the boot protocol version.&lt;&#x2F;li&gt;
&lt;li&gt;Hardware detection results from the real-mode setup code.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The kernel&#x27;s first initialization code reads this structure to learn about the machine. Without it, the kernel would not know how much RAM exists, what video mode is active, where the initrd is, or what command-line parameters the user requested.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Zero page (boot parameters)&lt;&#x2F;strong&gt;
A 4096-byte data structure that the bootloader and real-mode setup code fill in before jumping to the kernel. It contains the memory map, command line, initrd location, and hardware information. The kernel reads it during early initialization and never modifies or refers to it again after extracting the information it needs.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;summary-of-the-journey-so-far&quot;&gt;Summary of the Journey So Far&lt;&#x2F;h2&gt;
&lt;p&gt;From GRUB&#x27;s jump to the kernel&#x27;s first real instruction, a remarkable amount happens:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The real-mode setup code queries the BIOS for hardware information.&lt;&#x2F;li&gt;
&lt;li&gt;The A20 line is enabled.&lt;&#x2F;li&gt;
&lt;li&gt;A temporary GDT is loaded.&lt;&#x2F;li&gt;
&lt;li&gt;The CPU switches to protected mode, then to long mode.&lt;&#x2F;li&gt;
&lt;li&gt;The decompression stub extracts the compressed kernel.&lt;&#x2F;li&gt;
&lt;li&gt;The decompressed kernel is placed at its final physical address.&lt;&#x2F;li&gt;
&lt;li&gt;The stub jumps to the kernel entry point.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;All of this happens in a fraction of a second. The user sees nothing -- perhaps a brief flash on screen if verbose boot is enabled. But in that fraction of a second, the machine transforms from a BIOS-era 16-bit environment into a 64-bit system ready to initialize a modern operating system.&lt;&#x2F;p&gt;
&lt;p&gt;The kernel is now running. It has the CPU. It has the memory map. It has the initramfs. The next phase -- kernel initialization -- is where Linux truly comes to life.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;11-kernel-init&#x2F;&quot;&gt;Kernel Init&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Finding the Kernel</title>
        <published>2025-01-12T00:00:00+00:00</published>
        <updated>2025-01-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/10a-finding-the-kernel/"/>
        <id>https://t34ch.tech/coldboot/articles/10a-finding-the-kernel/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/10a-finding-the-kernel/">&lt;p&gt;GRUB has read its configuration, shown a menu, and the user (or the timeout) has selected an entry. The &lt;code&gt;linux&lt;&#x2F;code&gt; command in that entry specifies a path: something like &lt;code&gt;&#x2F;vmlinuz-6.2.0&lt;&#x2F;code&gt; or &lt;code&gt;&#x2F;boot&#x2F;vmlinuz-6.2.0&lt;&#x2F;code&gt;. GRUB must now find that file on disk, figure out what kind of image it is, and load it into the right place in memory.&lt;&#x2F;p&gt;
&lt;p&gt;This sounds simple, and for GRUB it mostly is -- GRUB has filesystem drivers that can read ext4, XFS, and other formats. But the kernel image itself is not straightforward. It is a compressed, multi-part file with a specific internal structure that GRUB must understand. The name &lt;code&gt;vmlinuz&lt;&#x2F;code&gt; hints at that structure, and the story behind it reaches back decades.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-the-kernel-lives&quot;&gt;Where the Kernel Lives&lt;&#x2F;h2&gt;
&lt;p&gt;On most Linux systems, kernel images live in &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt;. This directory is sometimes on the root filesystem and sometimes on a separate small partition. A separate &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt; partition was historically necessary because older bootloaders could not read beyond certain disk boundaries, or could not understand the root filesystem&#x27;s format. Today, GRUB can handle most filesystems and disk sizes, but the convention persists.&lt;&#x2F;p&gt;
&lt;p&gt;Inside &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt;, you will typically find several files for each installed kernel:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;&#x2F;boot&#x2F;vmlinuz-6.2.0-36-generic
&#x2F;boot&#x2F;initrd.img-6.2.0-36-generic
&#x2F;boot&#x2F;config-6.2.0-36-generic
&#x2F;boot&#x2F;System.map-6.2.0-36-generic
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The version number in each filename matches a specific kernel build. When you upgrade the kernel, your package manager installs new files with the new version number and runs &lt;code&gt;grub-mkconfig&lt;&#x2F;code&gt; to regenerate the GRUB configuration with updated paths.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: vmlinuz&lt;&#x2F;strong&gt;
The compressed Linux kernel image. The name comes from &quot;Virtual Memory LINUx&quot; with a &quot;z&quot; appended to indicate compression (like gzip). Despite the name, vmlinuz is not a standard compressed file -- it is a specially structured image containing a decompression stub, a setup header, and the compressed kernel proper.
&lt;&#x2F;div&gt;
&lt;p&gt;The symbolic link &lt;code&gt;&#x2F;vmlinuz&lt;&#x2F;code&gt; (in the root directory) often points to the latest installed kernel image in &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt;. GRUB configurations may reference either the full path or the symlink.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-kernel-image-format&quot;&gt;The Kernel Image Format&lt;&#x2F;h2&gt;
&lt;p&gt;The file &lt;code&gt;vmlinuz&lt;&#x2F;code&gt; is not a simple executable. It is not an ELF binary that you could run with a normal program loader. It is a custom format specific to the Linux boot process, and it contains several distinct parts packed together.&lt;&#x2F;p&gt;
&lt;p&gt;Think of it like a shipping container. The outside of the container has labels and handling instructions (the setup header). Inside the container is a smaller box containing the actual cargo, wrapped in packing material (the compressed kernel, surrounded by the decompression stub). You cannot use the cargo until you unpack the box.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 10a-1 -- Structure of a bzImage file&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 220&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;220&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Outer container --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;40&quot; width=&quot;540&quot; height=&quot;140&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;30&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;vmlinuz (bzImage)&lt;&#x2F;text&gt;
  &lt;!-- Boot sector + setup header --&gt;
  &lt;rect x=&quot;35&quot; y=&quot;55&quot; width=&quot;150&quot; height=&quot;110&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;110&quot; y=&quot;78&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Boot Sector&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;93&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;+&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;108&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Setup Header&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;130&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;real-mode code&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;~15 KB&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;157&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;(setup_sects sectors)&lt;&#x2F;text&gt;
  &lt;!-- Decompression stub --&gt;
  &lt;rect x=&quot;200&quot; y=&quot;55&quot; width=&quot;130&quot; height=&quot;110&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;265&quot; y=&quot;78&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Decompression&lt;&#x2F;text&gt;
  &lt;text x=&quot;265&quot; y=&quot;93&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Stub&lt;&#x2F;text&gt;
  &lt;text x=&quot;265&quot; y=&quot;120&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;small program&lt;&#x2F;text&gt;
  &lt;text x=&quot;265&quot; y=&quot;135&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;that unpacks&lt;&#x2F;text&gt;
  &lt;text x=&quot;265&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;the kernel&lt;&#x2F;text&gt;
  &lt;!-- Compressed kernel --&gt;
  &lt;rect x=&quot;345&quot; y=&quot;55&quot; width=&quot;200&quot; height=&quot;110&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;445&quot; y=&quot;78&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Compressed Kernel&lt;&#x2F;text&gt;
  &lt;text x=&quot;445&quot; y=&quot;100&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;(vmlinux.bin.gz)&lt;&#x2F;text&gt;
  &lt;text x=&quot;445&quot; y=&quot;125&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;the actual kernel&lt;&#x2F;text&gt;
  &lt;text x=&quot;445&quot; y=&quot;140&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;compressed with&lt;&#x2F;text&gt;
  &lt;text x=&quot;445&quot; y=&quot;155&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;gzip&#x2F;lz4&#x2F;zstd&#x2F;xz&lt;&#x2F;text&gt;
  &lt;!-- Arrows showing flow --&gt;
&lt;p&gt;&lt;text x=&quot;35&quot; y=&quot;195&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;GRUB reads this ---&amp;gt;&lt;&#x2F;text&gt;
&lt;text x=&quot;260&quot; y=&quot;195&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;to know how to load this ---&amp;gt;&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A bzImage contains three parts: the real-mode setup code with a header that describes the image, a small decompression stub, and the compressed kernel itself.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The three parts serve different purposes:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The boot sector and setup header&lt;&#x2F;strong&gt; occupy the first portion of the file. The boot sector is a legacy artifact -- it allows the kernel to be booted directly from a floppy disk without a bootloader. Nobody does this anymore, but the structure remains. The setup header, however, is critical. It contains fields that GRUB reads to know the kernel&#x27;s version, where to load it in memory, what boot protocol version it supports, and the size of the setup code.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The decompression stub&lt;&#x2F;strong&gt; is a small self-contained program. Its job is to decompress the next part. We will cover this in detail in the next article.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The compressed kernel&lt;&#x2F;strong&gt; is the actual Linux kernel -- the &lt;code&gt;vmlinux&lt;&#x2F;code&gt; ELF binary, stripped and then compressed with gzip, LZ4, LZMA, XZ, or Zstandard (depending on the kernel&#x27;s build configuration).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;vmlinux-vs-vmlinuz-vs-bzimage&quot;&gt;vmlinux vs. vmlinuz vs. bzImage&lt;&#x2F;h2&gt;
&lt;p&gt;These names are confusing because they evolved over decades and carry historical baggage. Here is the lineage:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;vmlinux&lt;&#x2F;strong&gt; is the raw, uncompressed Linux kernel. It is an ELF binary -- the direct output of the kernel build&#x27;s linking step. It contains debug symbols and section headers. On a modern kernel, it can be 30-80 MB or more. You will find it in the kernel build tree but almost never in &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;zImage&lt;&#x2F;strong&gt; was the original compressed kernel format. The &quot;z&quot; stands for the compression. It was limited to 512 KB of compressed data because it loaded the kernel below the 1 MB mark in memory (the real-mode address space). This limit made it unusable for modern kernels.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;bzImage&lt;&#x2F;strong&gt; stands for &quot;big zImage.&quot; It lifts the size restriction by loading the compressed kernel above the 1 MB mark. Despite the name containing &quot;bz,&quot; the compression is not bzip2 -- it was historically gzip, and modern kernels can use several algorithms. Nearly every Linux system today uses bzImage.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;vmlinuz&lt;&#x2F;strong&gt; is the file you find in &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt;. It is a bzImage -- the same file, just installed with a different name.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: bzImage&lt;&#x2F;strong&gt;
The standard format for a bootable Linux kernel image. &quot;Big zImage&quot; loads the compressed kernel above the 1 MB boundary, allowing much larger kernels than the original zImage format. The file installed as &#x2F;boot&#x2F;vmlinuz is a bzImage.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 10a-2 -- Kernel image name lineage&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 200&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;200&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- vmlinux --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;50&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;52&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;vmlinux&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;68&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;raw ELF, 30-80 MB&lt;&#x2F;text&gt;
  &lt;!-- Arrow: compress --&gt;
  &lt;line x1=&quot;170&quot; y1=&quot;55&quot; x2=&quot;210&quot; y2=&quot;55&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;210,50 220,55 210,60&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;text x=&quot;195&quot; y=&quot;45&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;strip +&lt;&#x2F;text&gt;
  &lt;text x=&quot;195&quot; y=&quot;34&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;compress&lt;&#x2F;text&gt;
  &lt;!-- vmlinux.bin.gz --&gt;
  &lt;rect x=&quot;225&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;50&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;295&quot; y=&quot;52&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;vmlinux.bin.gz&lt;&#x2F;text&gt;
  &lt;text x=&quot;295&quot; y=&quot;68&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;compressed, 8-12 MB&lt;&#x2F;text&gt;
  &lt;!-- Arrow: wrap --&gt;
  &lt;line x1=&quot;365&quot; y1=&quot;55&quot; x2=&quot;405&quot; y2=&quot;55&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;405,50 415,55 405,60&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
  &lt;text x=&quot;390&quot; y=&quot;45&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;add stub&lt;&#x2F;text&gt;
  &lt;text x=&quot;390&quot; y=&quot;34&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;+ header&lt;&#x2F;text&gt;
  &lt;!-- bzImage --&gt;
  &lt;rect x=&quot;420&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;50&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;490&quot; y=&quot;52&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;bzImage&lt;&#x2F;text&gt;
  &lt;text x=&quot;490&quot; y=&quot;68&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;bootable, 8-13 MB&lt;&#x2F;text&gt;
  &lt;!-- Installed as --&gt;
  &lt;line x1=&quot;490&quot; y1=&quot;80&quot; x2=&quot;490&quot; y2=&quot;110&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;polygon points=&quot;485,110 490,120 495,110&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;!-- vmlinuz --&gt;
  &lt;rect x=&quot;420&quot; y=&quot;125&quot; width=&quot;140&quot; height=&quot;45&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;490&quot; y=&quot;147&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;boot&#x2F;vmlinuz&lt;&#x2F;text&gt;
  &lt;text x=&quot;490&quot; y=&quot;161&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;same file, installed&lt;&#x2F;text&gt;
  &lt;!-- zImage (historical) --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;125&quot; width=&quot;140&quot; height=&quot;45&quot; fill=&quot;rgba(192,57,43,0.12)&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;147&quot; fill=&quot;#C0392B&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;zImage&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;161&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;historical, &amp;lt;512 KB&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The kernel build pipeline: vmlinux is compiled, stripped and compressed, then wrapped with a setup header and decompression stub to produce a bzImage. That bzImage is installed as &#x2F;boot&#x2F;vmlinuz.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-setup-header&quot;&gt;The Setup Header&lt;&#x2F;h2&gt;
&lt;p&gt;The setup header is the critical interface between the bootloader and the kernel. It is a binary structure starting at offset 0x01F1 in the kernel image, and it tells the bootloader everything it needs to know about how to load this particular kernel.&lt;&#x2F;p&gt;
&lt;p&gt;GRUB reads the following fields from the setup header:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;setup_sects&lt;&#x2F;strong&gt;: How many 512-byte sectors the setup code occupies. This tells GRUB where the protected-mode kernel code begins in the file.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;syssize&lt;&#x2F;strong&gt;: The size of the protected-mode code, in 16-byte paragraphs.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;boot_flag&lt;&#x2F;strong&gt;: Must be 0xAA55 (same magic number as the MBR, for historical reasons).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;header&lt;&#x2F;strong&gt;: Must be the magic string &quot;HdrS&quot; (0x53726448). This confirms the file is a valid Linux kernel image.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;version&lt;&#x2F;strong&gt;: The boot protocol version. Different versions support different features. Modern kernels use protocol 2.15 or higher.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;loadflags&lt;&#x2F;strong&gt;: Bit flags that control loading behavior. Bit 0 indicates whether the kernel was compiled as a bzImage (loaded high) or a zImage (loaded low).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;cmd_line_ptr&lt;&#x2F;strong&gt;: The physical address where GRUB should place the kernel command-line string.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;initrd_addr_max&lt;&#x2F;strong&gt;: The maximum physical address where the initrd can end. This prevents GRUB from loading the initrd above the kernel&#x27;s addressable range.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ramdisk_image&lt;&#x2F;strong&gt; and &lt;strong&gt;ramdisk_size&lt;&#x2F;strong&gt;: Where GRUB loaded the initrd and how large it is. GRUB fills these in so the kernel can find the initrd later.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Boot protocol&lt;&#x2F;strong&gt;
A versioned specification that defines the contract between the Linux kernel and the bootloader. The boot protocol defines which fields exist in the setup header, what values are valid, and what the bootloader must do before jumping to the kernel. The protocol version increments when new fields or capabilities are added.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 10a-3 -- Key setup header fields&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 320&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;320&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Header structure --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;Setup Header (starts at file offset 0x01F1)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Field entries --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;28&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;58&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;setup_sects&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;58&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Number of setup sectors (real-mode code size)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;74&quot; width=&quot;110&quot; height=&quot;28&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;92&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;header&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;92&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Magic &quot;HdrS&quot; = valid Linux kernel&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;108&quot; width=&quot;110&quot; height=&quot;28&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;126&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;version&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;126&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Boot protocol version (e.g. 0x020F = 2.15)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;142&quot; width=&quot;110&quot; height=&quot;28&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;160&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;loadflags&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;160&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Bit 0: loaded_high (1 = bzImage)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;176&quot; width=&quot;110&quot; height=&quot;28&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;194&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;cmd_line_ptr&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;194&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Address for kernel command line string&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;210&quot; width=&quot;110&quot; height=&quot;28&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;228&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;ramdisk_image&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;228&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Bootloader writes initrd load address here&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;244&quot; width=&quot;110&quot; height=&quot;28&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;262&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;ramdisk_size&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;262&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Bootloader writes initrd size here&lt;&#x2F;text&gt;
  &lt;rect x=&quot;40&quot; y=&quot;278&quot; width=&quot;110&quot; height=&quot;28&quot; fill=&quot;rgba(57,211,83,0.12)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;296&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;payload_offset&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;296&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;Offset to compressed kernel within the image&lt;&#x2F;text&gt;
  &lt;!-- Legend --&gt;
&lt;p&gt;&lt;text x=&quot;170&quot; y=&quot;58&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot;&gt;0x01F1&lt;&#x2F;text&gt;
&lt;text x=&quot;170&quot; y=&quot;92&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot;&gt;0x0202&lt;&#x2F;text&gt;
&lt;text x=&quot;170&quot; y=&quot;126&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot;&gt;0x0206&lt;&#x2F;text&gt;
&lt;text x=&quot;170&quot; y=&quot;160&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot;&gt;0x0211&lt;&#x2F;text&gt;
&lt;text x=&quot;170&quot; y=&quot;194&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot;&gt;0x0228&lt;&#x2F;text&gt;
&lt;text x=&quot;170&quot; y=&quot;228&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot;&gt;0x0218&lt;&#x2F;text&gt;
&lt;text x=&quot;170&quot; y=&quot;262&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot;&gt;0x021C&lt;&#x2F;text&gt;
&lt;text x=&quot;170&quot; y=&quot;296&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot;&gt;0x0248&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The setup header contains fields that GRUB reads (yellow, blue) and fields that GRUB writes (orange) to communicate with the kernel. The protocol version determines which fields are present.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;how-grub-loads-the-image&quot;&gt;How GRUB Loads the Image&lt;&#x2F;h2&gt;
&lt;p&gt;When GRUB processes the &lt;code&gt;linux&lt;&#x2F;code&gt; command, it executes a precise loading sequence:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open the file.&lt;&#x2F;strong&gt; GRUB uses its filesystem driver to open &lt;code&gt;vmlinuz&lt;&#x2F;code&gt; from the specified partition and path.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Read the setup header.&lt;&#x2F;strong&gt; GRUB reads the first few kilobytes of the file and parses the setup header starting at offset 0x01F1. It checks for the &quot;HdrS&quot; magic and the boot protocol version.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Validate the image.&lt;&#x2F;strong&gt; GRUB checks that the &lt;code&gt;loadflags&lt;&#x2F;code&gt; indicate a bzImage (it refuses to load a zImage on modern systems where the kernel would not fit below 1 MB). It verifies the protocol version is recent enough to support the features GRUB needs.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Load the real-mode code.&lt;&#x2F;strong&gt; The first &lt;code&gt;setup_sects + 1&lt;&#x2F;code&gt; sectors of the file (the boot sector plus the setup sectors) contain the real-mode kernel code. GRUB loads this to a low memory address, typically around 0x10000 (64 KB).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Load the protected-mode code.&lt;&#x2F;strong&gt; Everything after the setup sectors is the protected-mode kernel -- the decompression stub followed by the compressed kernel. GRUB loads this at the 1 MB mark (address 0x100000) or higher if the setup header specifies a preferred address.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Store boot parameters.&lt;&#x2F;strong&gt; GRUB writes the kernel command line to memory and records its address in &lt;code&gt;cmd_line_ptr&lt;&#x2F;code&gt;. It fills in the memory map, video mode information, and other fields in the boot parameters structure (the &quot;zero page&quot; at the start of the real-mode code segment).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;remember&quot;&gt;
The kernel image vmlinuz is a bzImage containing a setup header, a decompression stub, and the compressed kernel. GRUB reads the setup header to learn how to load the image, places the real-mode code in low memory and the protected-mode code above 1 MB, and fills in boot parameters so the kernel knows where everything is. The setup header is the contract between bootloader and kernel.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-initrd-companion&quot;&gt;The initrd Companion&lt;&#x2F;h2&gt;
&lt;p&gt;When GRUB processes the &lt;code&gt;initrd&lt;&#x2F;code&gt; command, it loads the initramfs image into memory above the kernel. The setup header field &lt;code&gt;initrd_addr_max&lt;&#x2F;code&gt; tells GRUB the highest address the kernel can access for the initrd, and GRUB loads it as high as possible within that limit (to leave room for the kernel to decompress and expand).&lt;&#x2F;p&gt;
&lt;p&gt;GRUB then writes the initrd&#x27;s physical address and size into the &lt;code&gt;ramdisk_image&lt;&#x2F;code&gt; and &lt;code&gt;ramdisk_size&lt;&#x2F;code&gt; fields of the boot parameters. The kernel will read these values during its initialization to find the initramfs.&lt;&#x2F;p&gt;
&lt;p&gt;The initrd is not optional on most systems. Without it, the kernel would need every driver compiled in -- SATA, NVMe, SCSI, USB, LVM, dm-crypt, every filesystem -- to mount the root partition. The initramfs provides exactly the drivers needed for this specific machine, keeping the kernel itself smaller and more generic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;finding-the-kernel-on-uefi&quot;&gt;Finding the Kernel on UEFI&lt;&#x2F;h2&gt;
&lt;p&gt;On UEFI systems, the process is slightly different but the kernel image format is the same. The UEFI version of GRUB reads files from the EFI System Partition (or from the &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt; partition, which GRUB can access via its filesystem modules). The kernel is still a bzImage with the same setup header.&lt;&#x2F;p&gt;
&lt;p&gt;One notable UEFI feature: modern Linux kernels (since about 2011, with the EFI boot stub) can be booted directly by the firmware without GRUB at all. The kernel&#x27;s EFI stub makes the bzImage look like a valid EFI application. The firmware loads it, the EFI stub runs, sets up the boot parameters itself, and jumps to the kernel. This is the basis of systemd-boot and other simple UEFI boot managers.&lt;&#x2F;p&gt;
&lt;p&gt;But whether GRUB or the firmware loads the image, the kernel&#x27;s internal structure is the same. The setup header, the decompression stub, and the compressed kernel are all present. The next step is always the same: decompress.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-happens-next&quot;&gt;What Happens Next&lt;&#x2F;h2&gt;
&lt;p&gt;GRUB has found the kernel file, parsed its setup header, loaded its real-mode and protected-mode parts into the correct memory addresses, and filled in the boot parameters. The initramfs is in memory too. Everything is staged and ready.&lt;&#x2F;p&gt;
&lt;p&gt;Now the CPU must jump to the kernel&#x27;s entry point. But the code it jumps to is not the kernel itself -- it is the decompression stub. The real kernel is still compressed, packed inside the bzImage. The stub must unpack it, and to do that, it first needs to leave real mode behind.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;10b-decompressing-and-handing-off&#x2F;&quot;&gt;Decompressing and Handing Off&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Stage 2: GRUB</title>
        <published>2025-01-11T00:00:00+00:00</published>
        <updated>2025-01-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/09-stage-2-grub/"/>
        <id>https://t34ch.tech/coldboot/articles/09-stage-2-grub/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/09-stage-2-grub/">&lt;p&gt;Stage 1 loaded a small piece of code that can read a filesystem. That code loaded GRUB&#x27;s main body into memory. Now, for the first time in the boot process, the machine is running a program that can do more than just load the next sector. GRUB can read configuration files, display a menu, accept keyboard input, and -- most importantly -- find and load a Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;GRUB stands for GRand Unified Bootloader. The &quot;unified&quot; part matters: GRUB can boot Linux, Windows, BSD, and other operating systems from a single menu. But its core job on a Linux system is straightforward. Read a config file. Show a menu. Load the kernel and an initial RAM filesystem into memory. Hand control to the kernel.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;grub-s-architecture&quot;&gt;GRUB&#x27;s Architecture&lt;&#x2F;h2&gt;
&lt;p&gt;GRUB is not a single program. It is a modular system built from a small core and a collection of loadable modules. The core provides the command-line interpreter, the module loader, and basic device access. Modules add specific capabilities: filesystem drivers, compression support, graphical terminal rendering, network booting, and more.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: GRUB module&lt;&#x2F;strong&gt;
A loadable piece of code that adds a specific capability to GRUB. Modules are stored as files in &#x2F;boot&#x2F;grub&#x2F; (or &#x2F;boot&#x2F;grub2&#x2F; on some distributions). Common modules include ext2.mod (for reading ext2&#x2F;ext3&#x2F;ext4 filesystems), normal.mod (the menu system), and linux.mod (for loading Linux kernels).
&lt;&#x2F;div&gt;
&lt;p&gt;When GRUB&#x27;s core starts, it loads the &lt;code&gt;normal&lt;&#x2F;code&gt; module, which provides the familiar menu interface. The &lt;code&gt;normal&lt;&#x2F;code&gt; module then reads the configuration file and builds the menu entries. If the configuration file is missing or corrupt, GRUB drops to a rescue shell -- a minimal command line where you can manually type commands to boot the system.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 09a -- GRUB modular architecture&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Core --&gt;
  &lt;rect x=&quot;190&quot; y=&quot;20&quot; width=&quot;200&quot; height=&quot;50&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;42&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot;&gt;GRUB Core&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;58&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;command line + module loader&lt;&#x2F;text&gt;
  &lt;!-- Module row 1 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;95&quot; width=&quot;105&quot; height=&quot;40&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;72&quot; y=&quot;115&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;normal.mod&lt;&#x2F;text&gt;
  &lt;text x=&quot;72&quot; y=&quot;127&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;menu system&lt;&#x2F;text&gt;
  &lt;rect x=&quot;138&quot; y=&quot;95&quot; width=&quot;105&quot; height=&quot;40&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;190&quot; y=&quot;115&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;ext2.mod&lt;&#x2F;text&gt;
  &lt;text x=&quot;190&quot; y=&quot;127&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;ext2&#x2F;3&#x2F;4 FS&lt;&#x2F;text&gt;
  &lt;rect x=&quot;256&quot; y=&quot;95&quot; width=&quot;105&quot; height=&quot;40&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;308&quot; y=&quot;115&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;linux.mod&lt;&#x2F;text&gt;
  &lt;text x=&quot;308&quot; y=&quot;127&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;kernel loader&lt;&#x2F;text&gt;
  &lt;rect x=&quot;374&quot; y=&quot;95&quot; width=&quot;105&quot; height=&quot;40&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;426&quot; y=&quot;115&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;gzio.mod&lt;&#x2F;text&gt;
  &lt;text x=&quot;426&quot; y=&quot;127&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;gzip decomp&lt;&#x2F;text&gt;
  &lt;!-- Module row 2 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;148&quot; width=&quot;105&quot; height=&quot;40&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;72&quot; y=&quot;168&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;xfs.mod&lt;&#x2F;text&gt;
  &lt;text x=&quot;72&quot; y=&quot;180&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;XFS FS&lt;&#x2F;text&gt;
  &lt;rect x=&quot;138&quot; y=&quot;148&quot; width=&quot;105&quot; height=&quot;40&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;190&quot; y=&quot;168&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;part_gpt.mod&lt;&#x2F;text&gt;
  &lt;text x=&quot;190&quot; y=&quot;180&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;GPT partitions&lt;&#x2F;text&gt;
  &lt;rect x=&quot;256&quot; y=&quot;148&quot; width=&quot;105&quot; height=&quot;40&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;308&quot; y=&quot;168&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;video.mod&lt;&#x2F;text&gt;
  &lt;text x=&quot;308&quot; y=&quot;180&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;framebuffer&lt;&#x2F;text&gt;
  &lt;rect x=&quot;374&quot; y=&quot;148&quot; width=&quot;105&quot; height=&quot;40&quot; fill=&quot;rgba(255,102,0,0.12)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;426&quot; y=&quot;168&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;...&lt;&#x2F;text&gt;
  &lt;text x=&quot;426&quot; y=&quot;180&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;100+ more&lt;&#x2F;text&gt;
  &lt;!-- Connecting lines --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;70&quot; x2=&quot;72&quot; y2=&quot;95&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;70&quot; x2=&quot;190&quot; y2=&quot;95&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;70&quot; x2=&quot;308&quot; y2=&quot;95&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;70&quot; x2=&quot;426&quot; y2=&quot;95&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Config file --&gt;
  &lt;rect x=&quot;180&quot; y=&quot;220&quot; width=&quot;220&quot; height=&quot;40&quot; fill=&quot;rgba(255,215,0,0.1)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;244&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;text&gt;
  &lt;line x1=&quot;72&quot; y1=&quot;135&quot; x2=&quot;290&quot; y2=&quot;220&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;text x=&quot;140&quot; y=&quot;195&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;normal.mod reads config&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;GRUB&#x27;s core loads modules on demand. The normal module reads grub.cfg and builds the boot menu. Filesystem modules let GRUB read files from partitions.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-configuration-file&quot;&gt;The Configuration File&lt;&#x2F;h2&gt;
&lt;p&gt;GRUB&#x27;s behavior is controlled by a file called &lt;code&gt;grub.cfg&lt;&#x2F;code&gt;, usually found at &lt;code&gt;&#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;code&gt; or &lt;code&gt;&#x2F;boot&#x2F;grub2&#x2F;grub.cfg&lt;&#x2F;code&gt;. You are not meant to edit this file by hand. It is generated automatically by the &lt;code&gt;grub-mkconfig&lt;&#x2F;code&gt; command (or &lt;code&gt;grub2-mkconfig&lt;&#x2F;code&gt; on Fedora&#x2F;RHEL systems), which scans your system for installed kernels and writes the appropriate menu entries.&lt;&#x2F;p&gt;
&lt;p&gt;A typical &lt;code&gt;grub.cfg&lt;&#x2F;code&gt; entry looks like this:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;menuentry &amp;#39;Ubuntu&amp;#39; --class ubuntu --class os {
    set root=&amp;#39;hd0,gpt2&amp;#39;
    linux &#x2F;vmlinuz-6.2.0 root=&#x2F;dev&#x2F;sda3 ro quiet splash
    initrd &#x2F;initrd.img-6.2.0
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each line does something specific:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;set root=&#x27;hd0,gpt2&#x27;&lt;&#x2F;code&gt; tells GRUB which partition to read files from. &lt;code&gt;hd0&lt;&#x2F;code&gt; is the first disk, &lt;code&gt;gpt2&lt;&#x2F;code&gt; is the second GPT partition.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;linux &#x2F;vmlinuz-6.2.0 ...&lt;&#x2F;code&gt; tells GRUB to load the kernel image from the specified path, and passes everything after the filename as kernel command-line parameters.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;initrd &#x2F;initrd.img-6.2.0&lt;&#x2F;code&gt; tells GRUB to load the initial RAM disk alongside the kernel.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: initrd &#x2F; initramfs&lt;&#x2F;strong&gt;
An initial RAM filesystem loaded into memory alongside the kernel. It contains a minimal set of drivers and tools that the kernel needs to mount the real root filesystem. Without it, the kernel could not access a root partition on LVM, RAID, an encrypted volume, or any device requiring a driver not compiled into the kernel itself.
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;how-grub-identifies-disks-and-partitions&quot;&gt;How GRUB Identifies Disks and Partitions&lt;&#x2F;h3&gt;
&lt;p&gt;GRUB uses its own naming convention for storage devices. The first hard disk is &lt;code&gt;hd0&lt;&#x2F;code&gt;, the second is &lt;code&gt;hd1&lt;&#x2F;code&gt;, and so on. Partitions are numbered starting from 1: &lt;code&gt;hd0,msdos1&lt;&#x2F;code&gt; for the first MBR partition on the first disk, or &lt;code&gt;hd0,gpt1&lt;&#x2F;code&gt; for the first GPT partition. This naming is independent of how Linux names the same devices (&lt;code&gt;&#x2F;dev&#x2F;sda1&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;dev&#x2F;nvme0n1p1&lt;&#x2F;code&gt;, etc.).&lt;&#x2F;p&gt;
&lt;p&gt;GRUB resolves these names using its disk and partition modules. It reads partition tables directly -- it does not rely on the operating system, because the operating system is not running yet. GRUB carries its own partition table parsers (&lt;code&gt;part_msdos.mod&lt;&#x2F;code&gt; for MBR, &lt;code&gt;part_gpt.mod&lt;&#x2F;code&gt; for GPT) and its own filesystem drivers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-grub-reads-filesystems&quot;&gt;How GRUB Reads Filesystems&lt;&#x2F;h2&gt;
&lt;p&gt;This is the capability that separates GRUB from the tiny Stage 1 code. Stage 1 can only read raw sectors by number. GRUB can read files by path.&lt;&#x2F;p&gt;
&lt;p&gt;GRUB includes filesystem driver modules for ext2&#x2F;ext3&#x2F;ext4, XFS, Btrfs, ZFS, FAT, NTFS, and others. When GRUB needs to read a file, it:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Identifies the disk and partition from the device name.&lt;&#x2F;li&gt;
&lt;li&gt;Reads the partition&#x27;s superblock to determine the filesystem type.&lt;&#x2F;li&gt;
&lt;li&gt;Loads the appropriate filesystem module if it is not already loaded.&lt;&#x2F;li&gt;
&lt;li&gt;Navigates the filesystem&#x27;s internal structures (inodes, directory entries, extent trees) to locate the file.&lt;&#x2F;li&gt;
&lt;li&gt;Reads the file&#x27;s data blocks into memory.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is the same work that the Linux kernel does when you run &lt;code&gt;cat &#x2F;boot&#x2F;vmlinuz&lt;&#x2F;code&gt;, but GRUB does it with its own code, running before the kernel exists. GRUB&#x27;s filesystem drivers are simpler than the kernel&#x27;s -- they only need to read, never write -- but they must be correct. A bug in GRUB&#x27;s ext4 driver means an unbootable system.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 09b -- GRUB reading a file from disk&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 260&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;260&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- GRUB box --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;50&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;52&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;GRUB Core&lt;&#x2F;text&gt;
  &lt;text x=&quot;90&quot; y=&quot;67&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;linux &#x2F;vmlinuz&lt;&#x2F;text&gt;
  &lt;!-- Arrow to FS module --&gt;
  &lt;line x1=&quot;160&quot; y1=&quot;55&quot; x2=&quot;195&quot; y2=&quot;55&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;195,50 205,55 195,60&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;!-- FS module --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;50&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;280&quot; y=&quot;52&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;ext2.mod&lt;&#x2F;text&gt;
  &lt;text x=&quot;280&quot; y=&quot;67&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;parse inode tree&lt;&#x2F;text&gt;
  &lt;!-- Arrow to disk --&gt;
  &lt;line x1=&quot;350&quot; y1=&quot;55&quot; x2=&quot;385&quot; y2=&quot;55&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;385,50 395,55 385,60&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;!-- Disk --&gt;
  &lt;rect x=&quot;400&quot; y=&quot;30&quot; width=&quot;140&quot; height=&quot;50&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;470&quot; y=&quot;52&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;BIOS INT 13h&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;67&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;read sectors&lt;&#x2F;text&gt;
  &lt;!-- Data flow back --&gt;
  &lt;path d=&quot;M 470 80 L 470 120 L 90 120 L 90 100&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; fill=&quot;none&quot; stroke-dasharray=&quot;6,3&quot;&#x2F;&gt;
  &lt;polygon points=&quot;85,100 90,90 95,100&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;280&quot; y=&quot;115&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;sector data returned&lt;&#x2F;text&gt;
  &lt;!-- Memory result --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;150&quot; width=&quot;520&quot; height=&quot;80&quot; fill=&quot;rgba(57,211,83,0.08)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;280&quot; y=&quot;172&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Memory at load address&lt;&#x2F;text&gt;
  &lt;!-- Kernel block --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;185&quot; width=&quot;240&quot; height=&quot;30&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;205&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;vmlinuz (kernel image)&lt;&#x2F;text&gt;
  &lt;!-- Initrd block --&gt;
  &lt;rect x=&quot;300&quot; y=&quot;185&quot; width=&quot;220&quot; height=&quot;30&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; rx=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;205&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;initrd.img (RAM disk)&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;GRUB uses its own filesystem driver to resolve file paths, reads the underlying sectors through BIOS services, and loads the kernel and initrd into specific memory addresses.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-menu-and-the-timeout&quot;&gt;The Menu and the Timeout&lt;&#x2F;h2&gt;
&lt;p&gt;When GRUB finishes loading its configuration, it displays a menu. If you have a single operating system, the menu might be hidden -- GRUB waits for a configurable timeout (often 5 or 10 seconds) and then boots the default entry automatically. Press Shift or Escape during this timeout to reveal the menu.&lt;&#x2F;p&gt;
&lt;p&gt;The menu lets you choose between different kernels (useful after a bad kernel upgrade), different operating systems (dual-boot setups), or recovery modes. Each menu entry is a &lt;code&gt;menuentry&lt;&#x2F;code&gt; block in &lt;code&gt;grub.cfg&lt;&#x2F;code&gt; containing the commands GRUB will execute when that entry is selected.&lt;&#x2F;p&gt;
&lt;p&gt;You can also press &lt;code&gt;c&lt;&#x2F;code&gt; at the menu to drop into GRUB&#x27;s command line, where you can type commands manually. This is invaluable for recovery. If your &lt;code&gt;grub.cfg&lt;&#x2F;code&gt; is corrupt but you know where your kernel lives, you can type:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;set root=(hd0,gpt2)
linux &#x2F;vmlinuz root=&#x2F;dev&#x2F;sda3
initrd &#x2F;initrd.img
boot
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Those four commands do exactly what a &lt;code&gt;menuentry&lt;&#x2F;code&gt; block does, but typed by hand.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
GRUB is a modular bootloader with its own filesystem drivers, command-line interpreter, and menu system. It reads a configuration file (grub.cfg) generated by your distribution&#x27;s tools, loads the kernel and initramfs into memory, and then hands control to the kernel. If the configuration is broken, you can use GRUB&#x27;s command line to boot manually.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;loading-the-kernel-and-initramfs&quot;&gt;Loading the Kernel and Initramfs&lt;&#x2F;h2&gt;
&lt;p&gt;When you select a menu entry (or the timeout expires), GRUB executes the commands in that entry. The &lt;code&gt;linux&lt;&#x2F;code&gt; command is the critical one. It does several things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Opens the kernel image file (&lt;code&gt;vmlinuz&lt;&#x2F;code&gt;) from the specified partition and path.&lt;&#x2F;li&gt;
&lt;li&gt;Reads the kernel&#x27;s setup header, which is embedded in the first few kilobytes of the image. The header tells GRUB the kernel&#x27;s version, required load address, command-line format, and other parameters.&lt;&#x2F;li&gt;
&lt;li&gt;Copies the kernel image into memory at the address the header specifies.&lt;&#x2F;li&gt;
&lt;li&gt;Stores the kernel command-line string (everything after the filename on the &lt;code&gt;linux&lt;&#x2F;code&gt; line) in a designated memory area.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The &lt;code&gt;initrd&lt;&#x2F;code&gt; command then loads the initial RAM filesystem image into another region of memory and records its address and size so the kernel can find it later.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 09c -- Memory layout after GRUB loads kernel and initrd&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Memory bar --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;20&quot; width=&quot;460&quot; height=&quot;260&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;15&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Physical Memory&lt;&#x2F;text&gt;
  &lt;!-- Real-mode code --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;35&quot; width=&quot;420&quot; height=&quot;35&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;52&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Real-mode kernel code + setup header&lt;&#x2F;text&gt;
  &lt;text x=&quot;510&quot; y=&quot;58&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0x10000&lt;&#x2F;text&gt;
  &lt;!-- Kernel command line --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;78&quot; width=&quot;420&quot; height=&quot;28&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;96&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Kernel command line (&quot;root=&#x2F;dev&#x2F;sda3 ro quiet&quot;)&lt;&#x2F;text&gt;
  &lt;!-- Gap --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;114&quot; width=&quot;420&quot; height=&quot;20&quot; fill=&quot;rgba(112,117,122,0.2)&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;128&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;...&lt;&#x2F;text&gt;
  &lt;!-- Protected-mode kernel --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;142&quot; width=&quot;420&quot; height=&quot;60&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;168&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Protected-mode kernel (compressed)&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;184&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;loaded at 0x100000 (1 MB mark)&lt;&#x2F;text&gt;
  &lt;!-- Gap --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;210&quot; width=&quot;420&quot; height=&quot;20&quot; fill=&quot;rgba(112,117,122,0.2)&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;224&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;...&lt;&#x2F;text&gt;
  &lt;!-- Initrd --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;238&quot; width=&quot;420&quot; height=&quot;30&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;258&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;initrd &#x2F; initramfs (loaded at high memory)&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;After GRUB&#x27;s linux and initrd commands execute, memory contains the kernel setup header at a low address, the compressed kernel at the 1 MB mark, and the initramfs image in high memory.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-boot-command&quot;&gt;The Boot Command&lt;&#x2F;h2&gt;
&lt;p&gt;After the &lt;code&gt;linux&lt;&#x2F;code&gt; and &lt;code&gt;initrd&lt;&#x2F;code&gt; commands have loaded their data, the &lt;code&gt;boot&lt;&#x2F;code&gt; command (usually implicit at the end of a &lt;code&gt;menuentry&lt;&#x2F;code&gt; block) triggers the actual handoff. GRUB fills in a data structure called the boot parameters (or &quot;zero page&quot;) with everything the kernel needs to know: the address and size of the initrd, the command-line location, the video mode, the memory map from the BIOS, and more.&lt;&#x2F;p&gt;
&lt;p&gt;Then GRUB jumps to the kernel&#x27;s entry point. At this moment, GRUB&#x27;s job is done. It will never run again (until the next reboot). The kernel takes over, and the bootloader is gone.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;grub-on-uefi-systems&quot;&gt;GRUB on UEFI Systems&lt;&#x2F;h2&gt;
&lt;p&gt;Everything described so far assumes legacy BIOS booting. On UEFI systems, the picture is different. UEFI firmware can read FAT-formatted partitions natively, so GRUB does not need the Stage 1 &#x2F; Stage 1.5 chain. Instead, GRUB is compiled as a UEFI application -- an EFI executable stored on the EFI System Partition (usually at &lt;code&gt;&#x2F;EFI&#x2F;ubuntu&#x2F;grubx64.efi&lt;&#x2F;code&gt; or similar).&lt;&#x2F;p&gt;
&lt;p&gt;The firmware loads this EFI application directly. There is no MBR boot code, no INT 0x13, no real mode. The UEFI version of GRUB uses UEFI boot services instead of BIOS interrupts for disk access and video output. But once GRUB is running, the user-facing experience is the same: same config file, same menu, same &lt;code&gt;linux&lt;&#x2F;code&gt; and &lt;code&gt;initrd&lt;&#x2F;code&gt; commands.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: EFI System Partition (ESP)&lt;&#x2F;strong&gt;
A FAT32-formatted partition that UEFI firmware can read directly. It contains bootloader executables (.efi files) and related configuration. On Linux systems, the ESP is usually mounted at &#x2F;boot&#x2F;efi or &#x2F;efi.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;when-things-go-wrong&quot;&gt;When Things Go Wrong&lt;&#x2F;h2&gt;
&lt;p&gt;GRUB failures are common enough that every Linux administrator encounters them. The most frequent scenarios:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&quot;error: unknown filesystem&quot;&lt;&#x2F;strong&gt; -- GRUB cannot read the partition containing its modules or configuration. This happens when a filesystem is corrupted, when you resize a partition without updating GRUB, or when a GRUB module for the filesystem type was not installed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&quot;error: file not found&quot;&lt;&#x2F;strong&gt; -- GRUB can read the filesystem but cannot find &lt;code&gt;grub.cfg&lt;&#x2F;code&gt; or the kernel. This happens after a kernel upgrade that did not regenerate &lt;code&gt;grub.cfg&lt;&#x2F;code&gt;, or after moving files around in &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Rescue shell&lt;&#x2F;strong&gt; -- GRUB loaded its core but could not load &lt;code&gt;normal.mod&lt;&#x2F;code&gt;. You get a &lt;code&gt;grub rescue&amp;gt;&lt;&#x2F;code&gt; prompt with minimal commands. The fix is usually &lt;code&gt;set prefix=(hd0,gpt2)&#x2F;boot&#x2F;grub&lt;&#x2F;code&gt; followed by &lt;code&gt;insmod normal&lt;&#x2F;code&gt; and then &lt;code&gt;normal&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In all these cases, the fix involves booting from a live USB, mounting the installed system, and running &lt;code&gt;grub-install&lt;&#x2F;code&gt; and &lt;code&gt;grub-mkconfig&lt;&#x2F;code&gt; to rebuild GRUB from scratch.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
GRUB&#x27;s power comes from its modularity. It carries its own filesystem drivers, so it can read files by path -- not just by sector number. It reads grub.cfg to build a menu, loads the kernel and initramfs into specific memory addresses, fills in the boot parameter structure, and jumps to the kernel entry point. From that jump onward, the bootloader is finished and the kernel is in control.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-happens-next&quot;&gt;What Happens Next&lt;&#x2F;h2&gt;
&lt;p&gt;GRUB has loaded the kernel image and the initramfs into memory. It has passed the kernel command line and a block of boot parameters. Now the kernel needs to actually start running. But the kernel image on disk is not a simple executable -- it is compressed, and it contains multiple parts. GRUB has found it; now the kernel must find itself.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;10a-finding-the-kernel&#x2F;&quot;&gt;Finding the Kernel&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Stage 1: The Bootloader</title>
        <published>2025-01-10T00:00:00+00:00</published>
        <updated>2025-01-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/08-stage-1-the-bootloader/"/>
        <id>https://t34ch.tech/coldboot/articles/08-stage-1-the-bootloader/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/08-stage-1-the-bootloader/">&lt;p&gt;In the previous article, the firmware found a boot device. It read the very first sector from that disk -- 512 bytes -- and loaded it into memory at address 0x7C00. Now the CPU&#x27;s instruction pointer is aimed at that address, and execution begins.&lt;&#x2F;p&gt;
&lt;p&gt;Those 512 bytes are the Master Boot Record, and the tiny program inside it is the Stage 1 bootloader. It is the smallest useful program in the entire boot chain. It has one job: load something bigger.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-512-byte-constraint&quot;&gt;The 512-Byte Constraint&lt;&#x2F;h2&gt;
&lt;p&gt;A single disk sector is 512 bytes. That is not a lot of space. To put it in perspective, this sentence alone is about 70 bytes of ASCII text. The entire Stage 1 bootloader has to fit in roughly seven sentences worth of raw data -- and that space is shared with other structures.&lt;&#x2F;p&gt;
&lt;p&gt;The 512-byte sector is divided into three regions. The first 440 bytes (sometimes 446, depending on the convention) hold executable machine code. The next 64 bytes hold the partition table -- four entries of 16 bytes each, describing how the disk is divided. The final 2 bytes hold the boot signature: 0x55 followed by 0xAA.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Master Boot Record (MBR)&lt;&#x2F;strong&gt;
The first 512-byte sector of a disk formatted with the traditional partitioning scheme. It contains boot code, a partition table, and a magic signature. The firmware checks the last two bytes for 0x55AA before treating the sector as bootable.
&lt;&#x2F;div&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 08a -- MBR layout (512 bytes)&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 200&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;200&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Offset labels --&gt;
&lt;p&gt;&lt;text x=&quot;40&quot; y=&quot;30&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;Offset&lt;&#x2F;text&gt;
&lt;text x=&quot;300&quot; y=&quot;30&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Contents&lt;&#x2F;text&gt;
&lt;text x=&quot;540&quot; y=&quot;30&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;Size&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Boot code region --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;45&quot; width=&quot;380&quot; height=&quot;40&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;15&quot; y=&quot;70&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;0x000&lt;&#x2F;text&gt;
  &lt;text x=&quot;240&quot; y=&quot;70&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Stage 1 Boot Code&lt;&#x2F;text&gt;
  &lt;text x=&quot;540&quot; y=&quot;70&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;440 bytes&lt;&#x2F;text&gt;
  &lt;!-- Disk signature --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;90&quot; width=&quot;380&quot; height=&quot;28&quot; fill=&quot;rgba(0,191,255,0.12)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;15&quot; y=&quot;108&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;0x1B8&lt;&#x2F;text&gt;
  &lt;text x=&quot;240&quot; y=&quot;108&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Disk Signature + Padding&lt;&#x2F;text&gt;
  &lt;text x=&quot;540&quot; y=&quot;108&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;6 bytes&lt;&#x2F;text&gt;
  &lt;!-- Partition table --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;123&quot; width=&quot;380&quot; height=&quot;28&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;15&quot; y=&quot;141&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;0x1BE&lt;&#x2F;text&gt;
  &lt;text x=&quot;240&quot; y=&quot;141&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Partition Table (4 entries)&lt;&#x2F;text&gt;
  &lt;text x=&quot;540&quot; y=&quot;141&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;64 bytes&lt;&#x2F;text&gt;
  &lt;!-- Boot signature --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;156&quot; width=&quot;380&quot; height=&quot;28&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; rx=&quot;3&quot;&#x2F;&gt;
  &lt;text x=&quot;15&quot; y=&quot;174&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;0x1FE&lt;&#x2F;text&gt;
  &lt;text x=&quot;240&quot; y=&quot;174&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;0x55 0xAA (Boot Signature)&lt;&#x2F;text&gt;
  &lt;text x=&quot;540&quot; y=&quot;174&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;2 bytes&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The 512-byte MBR is divided into boot code, a disk signature, a four-entry partition table, and the 0x55AA magic number.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The firmware does not care what the boot code does. It does not validate the instructions. It checks for 0x55AA, loads the sector, and jumps. From that point on, the boot code is in complete control.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;real-mode-the-1981-prison&quot;&gt;Real Mode: The 1981 Prison&lt;&#x2F;h2&gt;
&lt;p&gt;When the Stage 1 code starts running, the CPU is in real mode. This is the processor&#x27;s most primitive operating state -- the same mode the original IBM PC&#x27;s 8086 processor used in 1981. Every x86 processor since then, no matter how advanced, starts in this mode for backward compatibility.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Real mode&lt;&#x2F;strong&gt;
The CPU&#x27;s initial operating mode, inherited from the 8086. It provides direct access to hardware, uses 16-bit registers, and can address only 1 MB of memory. There is no memory protection, no privilege separation, and no virtual memory. Any instruction can access any address or any hardware port.
&lt;&#x2F;div&gt;
&lt;p&gt;Real mode imposes harsh constraints. The CPU uses 16-bit registers, which means a single register can hold a value between 0 and 65,535. Memory addresses use a segment:offset scheme where a 16-bit segment register is shifted left by 4 bits and added to a 16-bit offset, giving a 20-bit physical address. That is enough to address exactly 1,048,576 bytes -- one megabyte.&lt;&#x2F;p&gt;
&lt;p&gt;One megabyte sounds generous for 440 bytes of boot code, but the address space is not empty. The BIOS and hardware claim large chunks of it. The usable region for loading data is surprisingly small.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 08b -- Real mode memory map (first 1 MB)&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Memory bar --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;30&quot; width=&quot;60&quot; height=&quot;280&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Regions from bottom (0x00000) to top (0xFFFFF) --&gt;
  &lt;!-- IVT --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;275&quot; width=&quot;60&quot; height=&quot;35&quot; fill=&quot;rgba(192,57,43,0.3)&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;296&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;IVT (Interrupt Vector Table)&lt;&#x2F;text&gt;
  &lt;text x=&quot;65&quot; y=&quot;296&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0x00000&lt;&#x2F;text&gt;
  &lt;!-- BDA --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;260&quot; width=&quot;60&quot; height=&quot;15&quot; fill=&quot;rgba(192,57,43,0.2)&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;271&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;BIOS Data Area&lt;&#x2F;text&gt;
  &lt;text x=&quot;65&quot; y=&quot;271&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0x00400&lt;&#x2F;text&gt;
  &lt;!-- Free low memory --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;195&quot; width=&quot;60&quot; height=&quot;65&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;232&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Free (usable)&lt;&#x2F;text&gt;
  &lt;text x=&quot;65&quot; y=&quot;232&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0x00500&lt;&#x2F;text&gt;
  &lt;!-- MBR loaded here --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;180&quot; width=&quot;60&quot; height=&quot;15&quot; fill=&quot;rgba(255,215,0,0.3)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;191&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;MBR loaded here (0x7C00)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;187&quot; x2=&quot;155&quot; y2=&quot;187&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;none&quot;&#x2F;&gt;
  &lt;!-- More free --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;110&quot; width=&quot;60&quot; height=&quot;70&quot; fill=&quot;rgba(57,211,83,0.15)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;148&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Free (usable)&lt;&#x2F;text&gt;
  &lt;text x=&quot;65&quot; y=&quot;148&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0x7E00&lt;&#x2F;text&gt;
  &lt;!-- EBDA --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;90&quot; width=&quot;60&quot; height=&quot;20&quot; fill=&quot;rgba(255,102,0,0.2)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;104&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;Extended BIOS Data Area&lt;&#x2F;text&gt;
  &lt;text x=&quot;65&quot; y=&quot;104&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0x80000&lt;&#x2F;text&gt;
  &lt;!-- Video memory --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;60&quot; width=&quot;60&quot; height=&quot;30&quot; fill=&quot;rgba(0,191,255,0.15)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;78&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;Video Memory + ROMs&lt;&#x2F;text&gt;
  &lt;text x=&quot;65&quot; y=&quot;78&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0xA0000&lt;&#x2F;text&gt;
  &lt;!-- BIOS ROM --&gt;
  &lt;rect x=&quot;80&quot; y=&quot;30&quot; width=&quot;60&quot; height=&quot;30&quot; fill=&quot;rgba(192,57,43,0.3)&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;155&quot; y=&quot;48&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;BIOS ROM&lt;&#x2F;text&gt;
  &lt;text x=&quot;65&quot; y=&quot;48&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0xF0000&lt;&#x2F;text&gt;
  &lt;!-- Top label --&gt;
&lt;p&gt;&lt;text x=&quot;65&quot; y=&quot;28&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;0xFFFFF&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The first megabyte of address space. The MBR boot code runs from 0x7C00. Green regions are available for loading additional data. Red and blue regions are reserved by firmware and hardware.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Notice where the MBR loads: address 0x7C00. This is not at the bottom of memory (reserved for the interrupt vector table) and not at the top (reserved for the BIOS ROM and video hardware). It sits in a gap of free memory, chosen decades ago for the original IBM PC and preserved ever since.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-the-boot-code-actually-does&quot;&gt;What the Boot Code Actually Does&lt;&#x2F;h2&gt;
&lt;p&gt;The Stage 1 boot code has 440 bytes to work with. That is too small for a filesystem driver, too small for a configuration parser, too small for anything complicated. The code does the absolute minimum needed to load the next piece of the chain.&lt;&#x2F;p&gt;
&lt;p&gt;Here is the typical sequence:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set up segment registers.&lt;&#x2F;strong&gt; The code sets CS, DS, ES, and SS to known values. The firmware does not guarantee these are correct, so the boot code normalizes them immediately.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Relocate itself.&lt;&#x2F;strong&gt; Many bootloaders copy themselves from 0x7C00 to a lower address (often 0x0600) to free up the area around 0x7C00 for loading the next stage. Then they jump to the relocated copy and continue from there.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scan the partition table.&lt;&#x2F;strong&gt; The code reads the four 16-byte partition table entries starting at offset 0x1BE. It looks for the entry marked as &quot;active&quot; -- the one with 0x80 in its first byte. This is the bootable partition.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Load the first sector of the active partition.&lt;&#x2F;strong&gt; Using BIOS interrupt 0x13 (the disk read service), the code loads the first sector of the active partition into memory at 0x7C00 -- the same address the MBR was originally loaded to.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Jump to the loaded code.&lt;&#x2F;strong&gt; The CPU begins executing the newly loaded sector. This is the Volume Boot Record (VBR) of the active partition, and it typically contains the start of a larger bootloader.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: BIOS Interrupt 0x13&lt;&#x2F;strong&gt;
A firmware service for reading and writing disk sectors. The boot code places parameters in CPU registers (drive number, cylinder&#x2F;head&#x2F;sector address, buffer address) and triggers a software interrupt. The BIOS handles the actual hardware communication. This is the only way to read a disk in real mode without writing a hardware driver from scratch.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-bios-disk-interface&quot;&gt;The BIOS Disk Interface&lt;&#x2F;h2&gt;
&lt;p&gt;Reading from disk in real mode means using BIOS services. The CPU cannot talk to a SATA controller or NVMe drive directly -- those protocols require setup that only the firmware has done. Instead, the boot code uses INT 0x13 with function 0x02 (read sectors).&lt;&#x2F;p&gt;
&lt;p&gt;The original interface uses Cylinder-Head-Sector (CHS) addressing. You specify which cylinder, which head, and which sector to read. CHS has a hard limit: it can address about 8 GB of disk space. For disks larger than that, an extended interface (INT 0x13 with function 0x42) uses Logical Block Addressing (LBA), where sectors are numbered sequentially from zero.&lt;&#x2F;p&gt;
&lt;p&gt;The Stage 1 code in a modern bootloader like GRUB uses LBA when available. It checks whether the BIOS supports the extensions (INT 0x13, function 0x41) and falls back to CHS if not.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The Stage 1 bootloader has 440 bytes of executable space. It runs in real mode with a 1 MB address limit. Its only job is to find the active partition, load its first sector using BIOS disk services, and jump to it. Everything else -- filesystem parsing, user menus, kernel loading -- must wait for a larger program.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-chain-continues&quot;&gt;The Chain Continues&lt;&#x2F;h2&gt;
&lt;p&gt;The code that Stage 1 loads from the active partition is sometimes called the Volume Boot Record. For simple bootloaders, this might be enough to start an operating system directly. But for modern systems with large kernels, compressed images, and configuration files, even the VBR is too small.&lt;&#x2F;p&gt;
&lt;p&gt;This is why GRUB and similar bootloaders use a multi-stage design. Stage 1 loads a small intermediate piece (often called Stage 1.5), which contains just enough code to read a filesystem. That intermediate piece then loads the full Stage 2 from a known location on the partition.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 08c -- Boot chain: Stage 1 to Stage 2&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 180&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;180&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Stage 1 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;60&quot; width=&quot;120&quot; height=&quot;60&quot; fill=&quot;rgba(255,215,0,0.15)&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;85&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Stage 1&lt;&#x2F;text&gt;
  &lt;text x=&quot;80&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;440 bytes&lt;&#x2F;text&gt;
  &lt;text x=&quot;80&quot; y=&quot;112&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;MBR&lt;&#x2F;text&gt;
  &lt;!-- Arrow 1 --&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;90&quot; x2=&quot;175&quot; y2=&quot;90&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;175,85 185,90 175,95&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
  &lt;text x=&quot;162&quot; y=&quot;78&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;INT 13h&lt;&#x2F;text&gt;
  &lt;!-- Stage 1.5 --&gt;
  &lt;rect x=&quot;190&quot; y=&quot;60&quot; width=&quot;120&quot; height=&quot;60&quot; fill=&quot;rgba(0,191,255,0.15)&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;250&quot; y=&quot;85&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Stage 1.5&lt;&#x2F;text&gt;
  &lt;text x=&quot;250&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;~30 KB&lt;&#x2F;text&gt;
  &lt;text x=&quot;250&quot; y=&quot;112&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;FS driver&lt;&#x2F;text&gt;
  &lt;!-- Arrow 2 --&gt;
  &lt;line x1=&quot;310&quot; y1=&quot;90&quot; x2=&quot;345&quot; y2=&quot;90&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;345,85 355,90 345,95&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
  &lt;text x=&quot;332&quot; y=&quot;78&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;reads FS&lt;&#x2F;text&gt;
  &lt;!-- Stage 2 --&gt;
  &lt;rect x=&quot;360&quot; y=&quot;60&quot; width=&quot;120&quot; height=&quot;60&quot; fill=&quot;rgba(255,102,0,0.15)&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot; rx=&quot;4&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;85&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;Stage 2&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;~300 KB+&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;112&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;GRUB core&lt;&#x2F;text&gt;
  &lt;!-- Arrow 3 to kernel --&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;90&quot; x2=&quot;515&quot; y2=&quot;90&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;polygon points=&quot;515,85 525,90 515,95&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;552&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Kernel&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Labels --&gt;
&lt;p&gt;&lt;text x=&quot;80&quot; y=&quot;42&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;BIOS loads&lt;&#x2F;text&gt;
&lt;text x=&quot;80&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Sector 0 (LBA)&lt;&#x2F;text&gt;
&lt;text x=&quot;250&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Sectors 1-62&lt;&#x2F;text&gt;
&lt;text x=&quot;420&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;&#x2F;boot&#x2F;grub&#x2F;&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The boot chain progresses from smallest to largest. Each stage loads the next, adding capabilities (filesystem access, configuration parsing, kernel loading) as it goes.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h3 id=&quot;where-does-stage-1-5-live&quot;&gt;Where Does Stage 1.5 Live?&lt;&#x2F;h3&gt;
&lt;p&gt;On an MBR-partitioned disk, the first partition typically does not start until sector 63 (or sector 2048 on modern tools). The sectors between the MBR (sector 0) and the first partition form a gap. GRUB installs its Stage 1.5 -- called &lt;code&gt;core.img&lt;&#x2F;code&gt; -- in this gap. It contains enough code to understand a filesystem (ext4, XFS, Btrfs, or whatever &lt;code&gt;&#x2F;boot&lt;&#x2F;code&gt; uses) so it can find and load the full GRUB Stage 2.&lt;&#x2F;p&gt;
&lt;p&gt;On a GPT-partitioned disk, the partition entries occupy the sectors immediately after the protective MBR, so there is no convenient gap. Instead, GPT systems use a dedicated BIOS Boot Partition -- a small partition (typically 1 MB) with a specific type GUID, reserved for the bootloader&#x27;s intermediate code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-fragility-of-stage-1&quot;&gt;The Fragility of Stage 1&lt;&#x2F;h2&gt;
&lt;p&gt;The MBR is a single point of failure. If those 512 bytes are corrupted -- by a bug, a careless &lt;code&gt;dd&lt;&#x2F;code&gt; command, or malware -- the system will not boot. The firmware will either fail the 0x55AA check and move to the next device, or execute garbage instructions and crash.&lt;&#x2F;p&gt;
&lt;p&gt;This is why disk cloning tools and system administrators treat the MBR with care. Overwriting the first sector of a disk destroys the bootloader and the partition table in one stroke. Backup tools like &lt;code&gt;dd if=&#x2F;dev&#x2F;sda of=mbr.bin bs=512 count=1&lt;&#x2F;code&gt; exist specifically to preserve it.&lt;&#x2F;p&gt;
&lt;p&gt;The MBR design dates to 1983. It was built for disks measured in tens of megabytes. The 4-entry partition table can describe at most four primary partitions, and CHS addressing limits disk access to about 8 GB. These limitations are why GPT and UEFI eventually replaced the MBR scheme -- but legacy BIOS booting with MBR is still common, and understanding it explains why the newer systems were designed the way they were.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Stage 1 is the smallest link in the boot chain. It occupies 440 bytes inside the 512-byte MBR, runs in 16-bit real mode, and uses BIOS interrupts to load the next stage from disk. Its only job is to hand off to something bigger. Every modern bootloader (GRUB, syslinux, Windows Boot Manager) starts with this same tiny seed.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-happens-next&quot;&gt;What Happens Next&lt;&#x2F;h2&gt;
&lt;p&gt;Stage 1 has done its job. It found the active partition (or loaded GRUB&#x27;s core.img from the post-MBR gap), read it into memory, and jumped to it. The CPU is still in real mode. It still has only 1 MB of address space. But now there is a much larger program running -- one with enough code to read filesystems, parse configuration files, and present a menu.&lt;&#x2F;p&gt;
&lt;p&gt;That program is GRUB Stage 2, and it is the subject of the next article.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;09-stage-2-grub&#x2F;&quot;&gt;Stage 2: GRUB&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Finding the Boot Device</title>
        <published>2025-01-09T00:00:00+00:00</published>
        <updated>2025-01-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/07-finding-the-boot-device/"/>
        <id>https://t34ch.tech/coldboot/articles/07-finding-the-boot-device/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/07-finding-the-boot-device/">&lt;p&gt;The firmware has tested the hardware, trained the memory, and enumerated every bus. It knows what devices are connected. Now it faces a practical question: which one has an operating system on it?&lt;&#x2F;p&gt;
&lt;p&gt;A typical system might have an NVMe SSD, a SATA hard drive, a USB flash drive, and a network adapter. Any of them could potentially contain bootable code. The firmware needs a reliable method for deciding which one to try first, and a way to recognize bootable media when it finds one.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-boot-order&quot;&gt;The Boot Order&lt;&#x2F;h2&gt;
&lt;p&gt;Every firmware stores a list of boot devices, ordered by priority. This list lives in NVRAM -- a small region of non-volatile storage on the motherboard that persists across power cycles. When you enter the firmware setup screen and rearrange the boot order, you are editing this list.&lt;&#x2F;p&gt;
&lt;p&gt;The firmware works through the list from top to bottom. It tries the first entry. If that device is not present, or does not contain bootable data, the firmware moves to the next entry. If nothing on the list works, most systems display an error -- &quot;No bootable device found&quot; or similar -- and halt.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: NVRAM (Non-Volatile Random-Access Memory)&lt;&#x2F;strong&gt;
A small region of persistent storage on the motherboard, typically backed by flash memory or a battery-maintained CMOS chip. The firmware uses NVRAM to store configuration settings: boot order, date&#x2F;time, hardware preferences, and (on UEFI systems) boot variables that point to specific files on specific partitions.
&lt;&#x2F;div&gt;
&lt;p&gt;On legacy BIOS systems, the boot order is a simple list of device types: first hard disk, CD-ROM, USB, network. The firmware does not know about specific partitions or files. It just tries to read from each device in order.&lt;&#x2F;p&gt;
&lt;p&gt;On UEFI systems, the boot order is more specific. Each entry can point to a particular file on a particular partition of a particular disk. A UEFI boot entry might say: &quot;load &lt;code&gt;\EFI\ubuntu\shimx64.efi&lt;&#x2F;code&gt; from partition 1 of NVMe disk 0.&quot; This precision means UEFI systems can have multiple operating systems installed on the same disk, each with its own boot entry, without conflict.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 07a -- Boot order resolution&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 350&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;350&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- NVRAM boot list --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;20&quot; width=&quot;200&quot; height=&quot;180&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;45&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Boot Order (NVRAM)&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;50&quot; y=&quot;72&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;1. NVMe SSD&lt;&#x2F;text&gt;
&lt;text x=&quot;50&quot; y=&quot;95&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;2. USB Drive&lt;&#x2F;text&gt;
&lt;text x=&quot;50&quot; y=&quot;118&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;3. SATA HDD&lt;&#x2F;text&gt;
&lt;text x=&quot;50&quot; y=&quot;141&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;4. Network (PXE)&lt;&#x2F;text&gt;
&lt;text x=&quot;50&quot; y=&quot;164&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot;&gt;5. CD-ROM&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Arrow from entry 1 --&gt;
  &lt;line x1=&quot;230&quot; y1=&quot;67&quot; x2=&quot;280&quot; y2=&quot;67&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07g)&quot;&#x2F;&gt;
  &lt;!-- Try&#x2F;check flow --&gt;
  &lt;rect x=&quot;280&quot; y=&quot;50&quot; width=&quot;130&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;345&quot; y=&quot;72&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Try NVMe SSD&lt;&#x2F;text&gt;
  &lt;line x1=&quot;345&quot; y1=&quot;85&quot; x2=&quot;345&quot; y2=&quot;110&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07g)&quot;&#x2F;&gt;
  &lt;rect x=&quot;280&quot; y=&quot;110&quot; width=&quot;130&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;345&quot; y=&quot;125&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Read sector 0&lt;&#x2F;text&gt;
  &lt;text x=&quot;345&quot; y=&quot;139&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;or locate ESP&lt;&#x2F;text&gt;
  &lt;line x1=&quot;345&quot; y1=&quot;145&quot; x2=&quot;345&quot; y2=&quot;170&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07y)&quot;&#x2F;&gt;
  &lt;!-- Decision diamond --&gt;
  &lt;polygon points=&quot;345,170 405,200 345,230 285,200&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;345&quot; y=&quot;203&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bootable?&lt;&#x2F;text&gt;
  &lt;!-- Yes path --&gt;
  &lt;line x1=&quot;405&quot; y1=&quot;200&quot; x2=&quot;460&quot; y2=&quot;200&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07g)&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;193&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot;&gt;YES&lt;&#x2F;text&gt;
  &lt;rect x=&quot;460&quot; y=&quot;183&quot; width=&quot;100&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;510&quot; y=&quot;205&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Load it!&lt;&#x2F;text&gt;
  &lt;!-- No path --&gt;
  &lt;line x1=&quot;345&quot; y1=&quot;230&quot; x2=&quot;345&quot; y2=&quot;260&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07r)&quot;&#x2F;&gt;
  &lt;text x=&quot;360&quot; y=&quot;250&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot;&gt;NO&lt;&#x2F;text&gt;
  &lt;rect x=&quot;280&quot; y=&quot;260&quot; width=&quot;130&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;345&quot; y=&quot;282&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Try next entry&lt;&#x2F;text&gt;
  &lt;!-- Loop arrow back --&gt;
  &lt;path d=&quot;M 280,277 L 255,277 L 255,90 L 230,90&quot; fill=&quot;none&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;!-- Exhausted --&gt;
  &lt;line x1=&quot;345&quot; y1=&quot;295&quot; x2=&quot;345&quot; y2=&quot;320&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arrow07r)&quot;&#x2F;&gt;
  &lt;text x=&quot;345&quot; y=&quot;340&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;No bootable device found&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrow07g&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;10&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arrow07y&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;10&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arrow07r&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;10&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The firmware walks the boot order list top to bottom, testing each device for bootable signatures or files. The first success wins. If nothing works, boot fails.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;mbr-the-legacy-partition-table&quot;&gt;MBR: The Legacy Partition Table&lt;&#x2F;h2&gt;
&lt;p&gt;The Master Boot Record is the original PC disk format, dating back to 1983. It occupies the very first sector of the disk -- 512 bytes at LBA 0 (Logical Block Address zero). Those 512 bytes are divided into three parts.&lt;&#x2F;p&gt;
&lt;p&gt;The first 446 bytes contain executable code -- the bootstrap program. The next 64 bytes contain the partition table: four entries of 16 bytes each, describing up to four primary partitions. The final 2 bytes are a magic number: &lt;code&gt;0x55AA&lt;&#x2F;code&gt;. This signature tells the firmware that the sector contains valid boot code.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: MBR (Master Boot Record)&lt;&#x2F;strong&gt;
The first 512 bytes of a legacy-partitioned disk. It contains a small bootstrap program, a table of up to four partition entries, and a two-byte signature (0x55AA). The firmware loads this sector into memory and jumps to the code at offset zero.
&lt;&#x2F;div&gt;
&lt;p&gt;Each MBR partition entry contains a start address, a size (both in 32-bit LBA), a partition type byte, and a status byte. The status byte is either &lt;code&gt;0x80&lt;&#x2F;code&gt; (active, or &quot;bootable&quot;) or &lt;code&gt;0x00&lt;&#x2F;code&gt; (inactive). Only one partition should be marked active at a time. The bootstrap code in the MBR typically scans the partition table for the active partition, loads the first sector of that partition (the Volume Boot Record), and jumps to it.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 07b -- MBR structure (512 bytes)&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Byte offset ruler --&gt;
&lt;p&gt;&lt;text x=&quot;40&quot; y=&quot;25&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;Offset:&lt;&#x2F;text&gt;
&lt;text x=&quot;130&quot; y=&quot;25&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x000&lt;&#x2F;text&gt;
&lt;text x=&quot;330&quot; y=&quot;25&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x1BE&lt;&#x2F;text&gt;
&lt;text x=&quot;510&quot; y=&quot;25&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x1FE&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Bootstrap code block --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;35&quot; width=&quot;250&quot; height=&quot;60&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;165&quot; y=&quot;60&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Bootstrap Code&lt;&#x2F;text&gt;
  &lt;text x=&quot;165&quot; y=&quot;80&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;446 bytes of x86 machine code&lt;&#x2F;text&gt;
  &lt;!-- Partition table --&gt;
  &lt;rect x=&quot;295&quot; y=&quot;35&quot; width=&quot;200&quot; height=&quot;60&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;395&quot; y=&quot;60&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Partition Table&lt;&#x2F;text&gt;
  &lt;text x=&quot;395&quot; y=&quot;80&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;4 entries x 16 bytes = 64B&lt;&#x2F;text&gt;
  &lt;!-- Signature --&gt;
  &lt;rect x=&quot;500&quot; y=&quot;35&quot; width=&quot;50&quot; height=&quot;60&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;525&quot; y=&quot;62&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0x55&lt;&#x2F;text&gt;
  &lt;text x=&quot;525&quot; y=&quot;80&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;0xAA&lt;&#x2F;text&gt;
  &lt;!-- Partition entry detail --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;125&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Partition Entry Format (16 bytes each)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Entry fields --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;140&quot; width=&quot;60&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;70&quot; y=&quot;160&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Status&lt;&#x2F;text&gt;
  &lt;text x=&quot;70&quot; y=&quot;178&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;0x80&lt;&#x2F;text&gt;
  &lt;rect x=&quot;108&quot; y=&quot;140&quot; width=&quot;80&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;148&quot; y=&quot;160&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;CHS Start&lt;&#x2F;text&gt;
  &lt;text x=&quot;148&quot; y=&quot;178&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;3 bytes&lt;&#x2F;text&gt;
  &lt;rect x=&quot;196&quot; y=&quot;140&quot; width=&quot;60&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;226&quot; y=&quot;160&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Type&lt;&#x2F;text&gt;
  &lt;text x=&quot;226&quot; y=&quot;178&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;0x83&lt;&#x2F;text&gt;
  &lt;rect x=&quot;264&quot; y=&quot;140&quot; width=&quot;80&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;304&quot; y=&quot;160&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;CHS End&lt;&#x2F;text&gt;
  &lt;text x=&quot;304&quot; y=&quot;178&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;3 bytes&lt;&#x2F;text&gt;
  &lt;rect x=&quot;352&quot; y=&quot;140&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;402&quot; y=&quot;160&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;LBA Start&lt;&#x2F;text&gt;
  &lt;text x=&quot;402&quot; y=&quot;178&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;4 bytes&lt;&#x2F;text&gt;
  &lt;rect x=&quot;460&quot; y=&quot;140&quot; width=&quot;90&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;505&quot; y=&quot;160&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Size (LBA)&lt;&#x2F;text&gt;
  &lt;text x=&quot;505&quot; y=&quot;178&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;4 bytes&lt;&#x2F;text&gt;
  &lt;!-- Annotations --&gt;
&lt;p&gt;&lt;text x=&quot;70&quot; y=&quot;215&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;0x80 = active&lt;&#x2F;text&gt;
&lt;text x=&quot;70&quot; y=&quot;228&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;0x00 = inactive&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;226&quot; y=&quot;215&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;0x83 = Linux&lt;&#x2F;text&gt;
&lt;text x=&quot;226&quot; y=&quot;228&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;0x07 = NTFS&lt;&#x2F;text&gt;
&lt;text x=&quot;226&quot; y=&quot;241&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;0x82 = swap&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;402&quot; y=&quot;215&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;32-bit = max&lt;&#x2F;text&gt;
&lt;text x=&quot;402&quot; y=&quot;228&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;2 TiB disk&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The MBR packs bootstrap code, four partition entries, and a boot signature into exactly 512 bytes. The status byte marks which partition is &quot;active&quot; -- the one the bootstrap code should chain-load.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h3 id=&quot;the-boot-flag&quot;&gt;The Boot Flag&lt;&#x2F;h3&gt;
&lt;p&gt;The &quot;active&quot; status byte -- &lt;code&gt;0x80&lt;&#x2F;code&gt; -- is commonly called the boot flag. It is how the MBR bootstrap code decides which partition to load next. The firmware itself does not check the boot flag. The firmware only checks the &lt;code&gt;0x55AA&lt;&#x2F;code&gt; signature at the end of the sector. The boot flag is interpreted by the code within the MBR.&lt;&#x2F;p&gt;
&lt;p&gt;This is a subtle but important distinction. The firmware&#x27;s job is to find a disk with a valid MBR signature and execute the code there. That code is then responsible for finding the active partition and loading its boot sector. The firmware does not know or care about partitions. It only knows about whole disks.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mbr-limitations&quot;&gt;MBR Limitations&lt;&#x2F;h3&gt;
&lt;p&gt;MBR has two significant limitations. First, the four-partition limit. You can work around it using &quot;extended partitions&quot; -- one of the four primary entries can point to a chain of logical partitions -- but the scheme is fragile and complicates boot code. Second, the 32-bit LBA fields limit addressable disk space to 2 TiB with 512-byte sectors. There is no way to extend this without breaking the format.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gpt-the-modern-partition-table&quot;&gt;GPT: The Modern Partition Table&lt;&#x2F;h2&gt;
&lt;p&gt;The GUID Partition Table, introduced alongside UEFI, solves both of MBR&#x27;s problems. It uses 64-bit LBA fields, supporting disks up to 9.4 ZB (zettabytes) -- far beyond anything that exists today. It supports up to 128 partition entries by default, each identified by a 128-bit GUID.&lt;&#x2F;p&gt;
&lt;p&gt;A GPT disk starts with a protective MBR at LBA 0. This is a standard MBR with a single partition entry covering the entire disk, typed as &lt;code&gt;0xEE&lt;&#x2F;code&gt; (GPT protective). Its purpose is to prevent MBR-only tools from treating the disk as unpartitioned and overwriting the GPT data.&lt;&#x2F;p&gt;
&lt;p&gt;The actual GPT header lives at LBA 1. It contains a magic signature (&lt;code&gt;EFI PART&lt;&#x2F;code&gt;), the disk GUID, the number of partition entries, and the LBA of the partition entry array. The partition entries follow the header, typically occupying LBA 2 through 33.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: GPT (GUID Partition Table)&lt;&#x2F;strong&gt;
The modern partition table format used on UEFI systems. Each partition has a 128-bit type GUID and a 128-bit unique GUID. GPT supports 64-bit addressing (no practical disk size limit) and up to 128 partitions. A backup copy of the header and entries is stored at the end of the disk.
&lt;&#x2F;div&gt;
&lt;p&gt;GPT also stores a backup copy of the header and all partition entries at the end of the disk. If the primary header is corrupted, the firmware or OS can recover from the backup. MBR has no such redundancy.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-efi-system-partition-and-boot-discovery&quot;&gt;The EFI System Partition and Boot Discovery&lt;&#x2F;h3&gt;
&lt;p&gt;On a UEFI system, the firmware does not execute code from the first sector. Instead, it looks for an EFI System Partition -- a partition with the specific type GUID &lt;code&gt;C12A7328-F81F-11D2-BA4B-00A0C93EC93B&lt;&#x2F;code&gt;. This partition must be formatted as FAT32 (or FAT12&#x2F;FAT16 for small media).&lt;&#x2F;p&gt;
&lt;p&gt;The firmware reads the UEFI boot variables from NVRAM. Each variable specifies a file path on a specific partition of a specific disk. For example: &quot;disk 0, partition 1, &lt;code&gt;\EFI\fedora\shimx64.efi&lt;&#x2F;code&gt;.&quot; The firmware mounts the FAT32 partition, navigates to that path, and loads the EFI executable.&lt;&#x2F;p&gt;
&lt;p&gt;If no boot variable matches, or the specified file is missing, the firmware falls back to a default path: &lt;code&gt;\EFI\BOOT\BOOTX64.EFI&lt;&#x2F;code&gt; for 64-bit x86, &lt;code&gt;\EFI\BOOT\BOOTAA64.EFI&lt;&#x2F;code&gt; for ARM64. This fallback is what makes USB installation media work without special NVRAM configuration -- the installer puts a bootloader at the default path, and any UEFI system will find it.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 07c -- UEFI boot device discovery&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 350&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;350&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- NVRAM --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;20&quot; width=&quot;200&quot; height=&quot;100&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;42&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;UEFI Boot Variables&lt;&#x2F;text&gt;
  &lt;text x=&quot;45&quot; y=&quot;62&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot;&gt;Boot0001: NVMe0, Part1&lt;&#x2F;text&gt;
  &lt;text x=&quot;45&quot; y=&quot;77&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot;&gt;\EFI\ubuntu\shimx64.efi&lt;&#x2F;text&gt;
  &lt;text x=&quot;45&quot; y=&quot;97&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot;&gt;Boot0002: SATA0, Part1&lt;&#x2F;text&gt;
  &lt;text x=&quot;45&quot; y=&quot;112&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;\EFI\BOOT\BOOTX64.EFI&lt;&#x2F;text&gt;
  &lt;!-- Arrow to disk --&gt;
  &lt;line x1=&quot;230&quot; y1=&quot;60&quot; x2=&quot;280&quot; y2=&quot;60&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07c)&quot;&#x2F;&gt;
  &lt;!-- Disk structure --&gt;
  &lt;rect x=&quot;280&quot; y=&quot;20&quot; width=&quot;270&quot; height=&quot;140&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;415&quot; y=&quot;42&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;NVMe SSD (GPT)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;295&quot; y=&quot;52&quot; width=&quot;55&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;322&quot; y=&quot;71&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;P-MBR&lt;&#x2F;text&gt;
  &lt;rect x=&quot;355&quot; y=&quot;52&quot; width=&quot;55&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;382&quot; y=&quot;71&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;GPT Hdr&lt;&#x2F;text&gt;
  &lt;rect x=&quot;415&quot; y=&quot;52&quot; width=&quot;60&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;445&quot; y=&quot;71&quot; fill=&quot;#FFD700&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;ESP (P1)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;480&quot; y=&quot;52&quot; width=&quot;55&quot; height=&quot;30&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;507&quot; y=&quot;71&quot; fill=&quot;#39D353&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;Root (P2)&lt;&#x2F;text&gt;
  &lt;!-- ESP contents --&gt;
  &lt;rect x=&quot;310&quot; y=&quot;95&quot; width=&quot;220&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;112&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;ESP Contents (FAT32)&lt;&#x2F;text&gt;
  &lt;text x=&quot;325&quot; y=&quot;130&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot;&gt;\EFI\ubuntu\shimx64.efi&lt;&#x2F;text&gt;
  &lt;text x=&quot;325&quot; y=&quot;143&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot;&gt;\EFI\BOOT\BOOTX64.EFI&lt;&#x2F;text&gt;
  &lt;!-- Arrow from ESP entry --&gt;
  &lt;line x1=&quot;445&quot; y1=&quot;82&quot; x2=&quot;445&quot; y2=&quot;95&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;3,2&quot;&#x2F;&gt;
  &lt;!-- Load flow --&gt;
  &lt;line x1=&quot;420&quot; y1=&quot;150&quot; x2=&quot;420&quot; y2=&quot;185&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07g2)&quot;&#x2F;&gt;
  &lt;rect x=&quot;310&quot; y=&quot;185&quot; width=&quot;220&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;207&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Load shimx64.efi&lt;&#x2F;text&gt;
  &lt;line x1=&quot;420&quot; y1=&quot;220&quot; x2=&quot;420&quot; y2=&quot;245&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07g2)&quot;&#x2F;&gt;
  &lt;rect x=&quot;310&quot; y=&quot;245&quot; width=&quot;220&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;267&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Verify Secure Boot signature&lt;&#x2F;text&gt;
  &lt;line x1=&quot;420&quot; y1=&quot;280&quot; x2=&quot;420&quot; y2=&quot;305&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow07g2)&quot;&#x2F;&gt;
  &lt;rect x=&quot;310&quot; y=&quot;305&quot; width=&quot;220&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;327&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Execute bootloader&lt;&#x2F;text&gt;
  &lt;!-- Fallback note --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;185&quot; width=&quot;240&quot; height=&quot;55&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;150&quot; y=&quot;205&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;If boot variable fails:&lt;&#x2F;text&gt;
  &lt;text x=&quot;150&quot; y=&quot;225&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Try \EFI\BOOT\BOOTX64.EFI&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrow07c&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;10&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arrow07g2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;10&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;UEFI reads boot variables from NVRAM, locates the ESP on the specified disk, and loads the named EFI executable. If that fails, it falls back to the default boot path.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;network-boot-pxe&quot;&gt;Network Boot: PXE&lt;&#x2F;h2&gt;
&lt;p&gt;Not all boot devices are local disks. PXE -- Preboot Execution Environment -- allows a system to boot over the network. The firmware&#x27;s network stack sends a DHCP request to get an IP address. The DHCP response includes the address of a TFTP server and the filename of a boot program. The firmware downloads that program over TFTP and executes it.&lt;&#x2F;p&gt;
&lt;p&gt;PXE is essential in data centers and labs where hundreds of machines need to be installed or re-imaged without anyone plugging in USB drives. It is also the fallback when local disks fail -- a system with a dead SSD can PXE boot into a recovery environment.&lt;&#x2F;p&gt;
&lt;p&gt;On UEFI systems, network boot loads an EFI executable over TFTP or HTTP. On legacy BIOS systems, it loads a 16-bit bootstrap program called a Network Bootstrap Program (NBP). In both cases, the network boot entry is just another item in the boot order list, tried in sequence like any disk.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The firmware discovers boot devices by walking the boot order stored in NVRAM. For legacy BIOS, it looks for the 0x55AA signature in the first sector of each disk. For UEFI, it reads structured boot variables that point to specific EFI executables on specific partitions. PXE allows booting over the network when no local disk is available or desired.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;how-the-firmware-talks-to-disks&quot;&gt;How the Firmware Talks to Disks&lt;&#x2F;h2&gt;
&lt;p&gt;The firmware needs storage drivers to read from disks. On a legacy BIOS system, these drivers are the INT 13h interrupt routines -- firmware-provided functions that can read and write disk sectors. INT 13h is slow (it reads one sector at a time through the CPU) and limited, but it works for the boot process.&lt;&#x2F;p&gt;
&lt;p&gt;On a UEFI system, the firmware loads Block I&#x2F;O Protocol drivers during the DXE phase. These drivers can talk to NVMe controllers, SATA controllers, and USB mass storage devices. The firmware also loads a Simple File System Protocol driver for FAT32, which is how it reads files from the ESP. These drivers are full 64-bit code with access to all system memory -- a far cry from the 16-bit, 1 MB world of INT 13h.&lt;&#x2F;p&gt;
&lt;p&gt;The firmware does not need to understand every filesystem. It only needs FAT32 for reading the ESP. The operating system brings its own drivers for ext4, NTFS, XFS, Btrfs, and everything else. The firmware&#x27;s job is strictly to get the bootloader loaded and running.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;removable-media-and-hot-plug&quot;&gt;Removable Media and Hot-Plug&lt;&#x2F;h2&gt;
&lt;p&gt;USB drives and optical media add a complication: they can be inserted after power-on. The firmware must periodically re-scan USB buses to detect new devices. Most UEFI implementations do this automatically. Legacy BIOS systems vary -- some re-scan USB at boot menu time, others only detect devices that were present at POST.&lt;&#x2F;p&gt;
&lt;p&gt;This is why the timing of inserting a USB boot drive matters. On some systems, you need to plug in the USB drive before powering on. On others, you can insert it at the boot menu. UEFI systems are generally more flexible because their USB drivers run continuously during the firmware phase.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 07d -- Boot media detection methods compared&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 260&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;260&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;How Firmware Validates Boot Media&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- BIOS column --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;45&quot; width=&quot;245&quot; height=&quot;195&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;152&quot; y=&quot;70&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Legacy BIOS&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;50&quot; y=&quot;95&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;1. Read LBA 0 (512 bytes)&lt;&#x2F;text&gt;
&lt;text x=&quot;50&quot; y=&quot;115&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;2. Check bytes 510-511&lt;&#x2F;text&gt;
&lt;text x=&quot;65&quot; y=&quot;133&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;Must be 0x55 0xAA&lt;&#x2F;text&gt;
&lt;text x=&quot;50&quot; y=&quot;155&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;3. Copy sector to 0x7C00&lt;&#x2F;text&gt;
&lt;text x=&quot;50&quot; y=&quot;175&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;4. Jump to 0x7C00&lt;&#x2F;text&gt;
&lt;line x1=&quot;50&quot; y1=&quot;185&quot; x2=&quot;255&quot; y2=&quot;185&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
&lt;text x=&quot;50&quot; y=&quot;205&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;No signature check&lt;&#x2F;text&gt;
&lt;text x=&quot;50&quot; y=&quot;222&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;No file path awareness&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- UEFI column --&gt;
  &lt;rect x=&quot;305&quot; y=&quot;45&quot; width=&quot;245&quot; height=&quot;195&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;427&quot; y=&quot;70&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;UEFI&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;325&quot; y=&quot;95&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;1. Read GPT, find ESP&lt;&#x2F;text&gt;
&lt;text x=&quot;325&quot; y=&quot;115&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;2. Mount FAT32 filesystem&lt;&#x2F;text&gt;
&lt;text x=&quot;325&quot; y=&quot;135&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;3. Locate .EFI file by path&lt;&#x2F;text&gt;
&lt;text x=&quot;325&quot; y=&quot;155&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;4. Verify Secure Boot sig&lt;&#x2F;text&gt;
&lt;text x=&quot;325&quot; y=&quot;175&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;5. Load into memory, execute&lt;&#x2F;text&gt;
&lt;line x1=&quot;325&quot; y1=&quot;185&quot; x2=&quot;530&quot; y2=&quot;185&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
&lt;text x=&quot;325&quot; y=&quot;205&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Cryptographic verification&lt;&#x2F;text&gt;
&lt;text x=&quot;325&quot; y=&quot;222&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Named file on known path&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;BIOS trusts a two-byte magic number. UEFI verifies a cryptographic signature on a named file. The difference in security posture is enormous.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;putting-it-together&quot;&gt;Putting It Together&lt;&#x2F;h2&gt;
&lt;p&gt;Here is the complete sequence, from the moment the firmware starts looking for a boot device to the moment it hands off to the bootloader:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The firmware reads the boot order from NVRAM.&lt;&#x2F;li&gt;
&lt;li&gt;For each entry, it checks whether the device is present.&lt;&#x2F;li&gt;
&lt;li&gt;If present, it reads the disk&#x27;s partition table (MBR or GPT).&lt;&#x2F;li&gt;
&lt;li&gt;On a BIOS system: it checks the MBR for the &lt;code&gt;0x55AA&lt;&#x2F;code&gt; signature, loads the 512-byte sector to memory address &lt;code&gt;0x7C00&lt;&#x2F;code&gt;, and jumps to it.&lt;&#x2F;li&gt;
&lt;li&gt;On a UEFI system: it locates the ESP, mounts the FAT32 filesystem, finds the specified EFI file, optionally verifies its Secure Boot signature, loads it into memory, and calls its entry point.&lt;&#x2F;li&gt;
&lt;li&gt;If the boot attempt fails, it moves to the next entry in the boot order.&lt;&#x2F;li&gt;
&lt;li&gt;If all entries fail, it displays an error and halts (or offers a setup menu).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;remember&quot;&gt;
Finding the boot device is a search problem with a strict protocol. The firmware does not guess. It follows the boot order list, checks each device against known criteria (MBR signature or ESP with an EFI executable), and loads the first thing that passes the test. This is the last step the firmware performs on its own. From here, control passes to the bootloader -- the first piece of software that was chosen by the user or the OS installer, not by the hardware vendor.
&lt;&#x2F;div&gt;
&lt;p&gt;The firmware&#x27;s work is now done. The bootloader it loaded will take over, find the operating system kernel, and begin the process of bringing up a full OS. That is the next chapter in the boot sequence.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;08-stage-1-the-bootloader&#x2F;&quot;&gt;Stage 1: The Bootloader&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Bus System</title>
        <published>2025-01-08T00:00:00+00:00</published>
        <updated>2025-01-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/06-the-bus-system/"/>
        <id>https://t34ch.tech/coldboot/articles/06-the-bus-system/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/06-the-bus-system/">&lt;p&gt;A CPU by itself can compute, but it cannot do anything useful without talking to other hardware: disks to read from, displays to write to, network adapters to send packets through. The wires and protocols that connect the CPU to everything else are called buses. The bus system is how a computer becomes more than a processor in a void.&lt;&#x2F;p&gt;
&lt;p&gt;During boot, the firmware must discover every device attached to every bus, assign each one an address, and configure it so the operating system can use it later. This process is called bus enumeration, and it happens before the OS loads.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-a-bus-actually-is&quot;&gt;What a Bus Actually Is&lt;&#x2F;h2&gt;
&lt;p&gt;A bus is a shared communication channel. In the simplest case, it is a set of parallel wires connecting two or more components. One device puts data on the wires, another reads it off. A protocol defines who gets to talk when and how addresses are specified.&lt;&#x2F;p&gt;
&lt;p&gt;Think of a bus as a shared hallway in an apartment building. Anyone can walk down it, but there are rules: you do not block the hallway, you knock on the right door, and you wait your turn. The hallway itself is just space -- the rules are what make it work.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Bus&lt;&#x2F;strong&gt;
A communication pathway shared by multiple devices. A bus includes the physical wires (or lanes), a protocol defining how data is transferred, and an addressing scheme so each device knows which messages are meant for it.
&lt;&#x2F;div&gt;
&lt;p&gt;Early personal computers had a single bus for everything. The original IBM PC&#x27;s ISA bus carried CPU instructions, memory access, and I&#x2F;O device communication on the same set of wires. Modern systems split this into several specialized buses, each optimized for different types of traffic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-modern-bus-hierarchy&quot;&gt;The Modern Bus Hierarchy&lt;&#x2F;h2&gt;
&lt;p&gt;A modern x86 system has a layered bus hierarchy. The CPU sits at the top. It connects to memory through dedicated high-speed channels (the memory bus, which we covered in the previous article). It connects to everything else through a hierarchy of buses that branch out like a tree.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 06a -- Modern bus hierarchy&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 380&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;380&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- CPU --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;15&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;5&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;43&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;CPU&lt;&#x2F;text&gt;
  &lt;!-- Memory bus (left) --&gt;
  &lt;line x1=&quot;250&quot; y1=&quot;60&quot; x2=&quot;100&quot; y2=&quot;100&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;rect x=&quot;30&quot; y=&quot;100&quot; width=&quot;140&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;125&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;DDR Memory&lt;&#x2F;text&gt;
  &lt;!-- PCIe root (center) --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;60&quot; x2=&quot;290&quot; y2=&quot;90&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;rect x=&quot;210&quot; y=&quot;90&quot; width=&quot;160&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;115&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;PCIe Root Complex&lt;&#x2F;text&gt;
  &lt;!-- PCIe branches --&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;130&quot; x2=&quot;100&quot; y2=&quot;170&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;130&quot; x2=&quot;290&quot; y2=&quot;170&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;340&quot; y1=&quot;130&quot; x2=&quot;480&quot; y2=&quot;170&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- GPU --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;170&quot; width=&quot;140&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;195&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;GPU (x16)&lt;&#x2F;text&gt;
  &lt;!-- NVMe --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;170&quot; width=&quot;140&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;195&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;NVMe SSD (x4)&lt;&#x2F;text&gt;
  &lt;!-- Chipset --&gt;
  &lt;rect x=&quot;410&quot; y=&quot;170&quot; width=&quot;140&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;195&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Chipset (PCH)&lt;&#x2F;text&gt;
  &lt;!-- Chipset children --&gt;
  &lt;line x1=&quot;440&quot; y1=&quot;210&quot; x2=&quot;80&quot; y2=&quot;260&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;460&quot; y1=&quot;210&quot; x2=&quot;240&quot; y2=&quot;260&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;210&quot; x2=&quot;400&quot; y2=&quot;260&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;510&quot; y1=&quot;210&quot; x2=&quot;520&quot; y2=&quot;260&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- SATA --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;260&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;282&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;SATA controller&lt;&#x2F;text&gt;
  &lt;!-- USB --&gt;
  &lt;rect x=&quot;170&quot; y=&quot;260&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;230&quot; y=&quot;282&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;USB controller&lt;&#x2F;text&gt;
  &lt;!-- Ethernet --&gt;
  &lt;rect x=&quot;340&quot; y=&quot;260&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;400&quot; y=&quot;282&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Ethernet (GbE)&lt;&#x2F;text&gt;
  &lt;!-- Audio --&gt;
  &lt;rect x=&quot;475&quot; y=&quot;260&quot; width=&quot;85&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;517&quot; y=&quot;282&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Audio&lt;&#x2F;text&gt;
  &lt;!-- Downstream devices --&gt;
  &lt;line x1=&quot;80&quot; y1=&quot;295&quot; x2=&quot;80&quot; y2=&quot;320&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;335&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;HDD &#x2F; SSD&lt;&#x2F;text&gt;
  &lt;line x1=&quot;230&quot; y1=&quot;295&quot; x2=&quot;230&quot; y2=&quot;320&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;230&quot; y=&quot;335&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Keyboard &#x2F; Mouse&lt;&#x2F;text&gt;
  &lt;line x1=&quot;400&quot; y1=&quot;295&quot; x2=&quot;400&quot; y2=&quot;320&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;400&quot; y=&quot;335&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Network cable&lt;&#x2F;text&gt;
  &lt;!-- Bandwidth labels --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;370&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bandwidth decreases as you move away from the CPU&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The CPU connects to memory directly and to everything else through PCIe. High-bandwidth devices (GPU, NVMe) connect to the CPU&#x27;s PCIe root complex. Lower-speed devices connect through the chipset, which itself is a PCIe device.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The key component between the CPU and most peripherals is the chipset, which Intel calls the Platform Controller Hub (PCH) and AMD calls the Fusion Controller Hub (FCH). The chipset connects to the CPU through a dedicated PCIe link and provides the buses for lower-speed devices: SATA ports, USB controllers, audio, Ethernet, and additional PCIe slots.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pcie-the-backbone&quot;&gt;PCIe: The Backbone&lt;&#x2F;h2&gt;
&lt;p&gt;PCI Express (PCIe) is the dominant interconnect in modern computers. It replaced the older PCI and AGP buses. Unlike those parallel buses, PCIe uses serial point-to-point connections called lanes. Each lane is a pair of differential signal pairs -- one pair for sending, one for receiving -- so data flows in both directions simultaneously.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: PCIe Lane&lt;&#x2F;strong&gt;
A single bidirectional serial link made of two pairs of wires (four wires total). Each lane can transfer data in both directions at the same time. Devices are connected with x1, x4, x8, or x16 lanes depending on how much bandwidth they need.
&lt;&#x2F;div&gt;
&lt;p&gt;A PCIe x1 link has one lane. A x16 slot has sixteen lanes. A single PCIe 4.0 lane delivers about 2 GB&#x2F;s in each direction. A x16 GPU slot therefore provides roughly 32 GB&#x2F;s of bandwidth to the graphics card. An NVMe SSD typically uses a x4 link, giving it about 8 GB&#x2F;s.&lt;&#x2F;p&gt;
&lt;p&gt;PCIe is not a shared bus in the traditional sense. Each device has its own dedicated link to either the CPU&#x27;s root complex or the chipset. There is no contention for wire time the way there was on the old PCI bus. If two PCIe devices want to send data at the same time, they can -- they are on separate wires.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pcie-enumeration&quot;&gt;PCIe Enumeration&lt;&#x2F;h3&gt;
&lt;p&gt;At boot, the firmware must discover every PCIe device in the system. It does this by walking the bus hierarchy.&lt;&#x2F;p&gt;
&lt;p&gt;PCIe uses a tree topology. The root complex is at the top. Below it are bridges (or switches) that fan out to more devices. Each device has a configuration space -- a block of registers at a known address that describes the device: its vendor ID, device ID, what class of device it is (storage, network, display, etc.), and what resources it needs (memory ranges, I&#x2F;O ports, interrupt lines).&lt;&#x2F;p&gt;
&lt;p&gt;The firmware scans this tree by reading the configuration space at every possible bus&#x2F;device&#x2F;function address. If something responds, the firmware records it and assigns it resources. If nothing responds, the firmware moves on. This process is called enumeration.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 06b -- PCIe enumeration: scanning the tree&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Header --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;PCIe Configuration Space Scan&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Bus 0 --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;40&quot; width=&quot;160&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;60&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Root Complex (Bus 0)&lt;&#x2F;text&gt;
  &lt;!-- Scan lines --&gt;
  &lt;line x1=&quot;250&quot; y1=&quot;70&quot; x2=&quot;120&quot; y2=&quot;100&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;70&quot; x2=&quot;290&quot; y2=&quot;100&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;330&quot; y1=&quot;70&quot; x2=&quot;460&quot; y2=&quot;100&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- Device 0:0 --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;100&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;120&quot; y=&quot;118&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bus 0, Dev 0&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;135&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;GPU: 10de:2684&lt;&#x2F;text&gt;
  &lt;!-- Device 0:1 (bridge) --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;100&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;118&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bus 0, Dev 1&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;135&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;PCIe Bridge&lt;&#x2F;text&gt;
  &lt;!-- Device 0:2 --&gt;
  &lt;rect x=&quot;390&quot; y=&quot;100&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;460&quot; y=&quot;118&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bus 0, Dev 2&lt;&#x2F;text&gt;
  &lt;text x=&quot;460&quot; y=&quot;135&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;NVMe: 144d:a80a&lt;&#x2F;text&gt;
  &lt;!-- Bridge to Bus 1 --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;145&quot; x2=&quot;290&quot; y2=&quot;175&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;310&quot; y=&quot;165&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot;&gt;Bus 1&lt;&#x2F;text&gt;
  &lt;!-- Bus 1 devices --&gt;
  &lt;line x1=&quot;260&quot; y1=&quot;175&quot; x2=&quot;170&quot; y2=&quot;200&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;320&quot; y1=&quot;175&quot; x2=&quot;410&quot; y2=&quot;200&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;100&quot; y=&quot;200&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;170&quot; y=&quot;218&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bus 1, Dev 0&lt;&#x2F;text&gt;
  &lt;text x=&quot;170&quot; y=&quot;235&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Ethernet: 8086:15b8&lt;&#x2F;text&gt;
  &lt;rect x=&quot;340&quot; y=&quot;200&quot; width=&quot;140&quot; height=&quot;45&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;218&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bus 1, Dev 1&lt;&#x2F;text&gt;
  &lt;text x=&quot;410&quot; y=&quot;235&quot; fill=&quot;#C0392B&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;No response&lt;&#x2F;text&gt;
  &lt;!-- Legend --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;265&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;60&quot; y=&quot;275&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Device found&lt;&#x2F;text&gt;
  &lt;rect x=&quot;180&quot; y=&quot;265&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;200&quot; y=&quot;275&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;No device (skip)&lt;&#x2F;text&gt;
  &lt;rect x=&quot;340&quot; y=&quot;265&quot; width=&quot;12&quot; height=&quot;12&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;360&quot; y=&quot;275&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;Bridge (scan sub-bus)&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The firmware reads configuration registers at each possible address. Devices that respond get recorded and assigned resources. Bridges reveal additional buses to scan.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Every PCIe device has a 256-byte (PCIe extends this to 4096 bytes) configuration space. The first 64 bytes are standardized. Byte 0 and 1 are the vendor ID. Bytes 2 and 3 are the device ID. The class code at offset 0x09-0x0B tells the firmware what kind of device it is -- mass storage, network controller, display adapter, and so on. The firmware does not need a device-specific driver to enumerate PCIe. It just reads these standard registers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;address-spaces-memory-mapped-i-o&quot;&gt;Address Spaces: Memory-Mapped I&#x2F;O&lt;&#x2F;h2&gt;
&lt;p&gt;When the firmware assigns resources to a device, it gives that device a range of memory addresses. But these addresses do not point to RAM. They point to the device itself. When the CPU reads or writes to one of these addresses, the transaction travels over the PCIe bus to the device instead of to DRAM. This is called memory-mapped I&#x2F;O, or MMIO.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Memory-Mapped I&#x2F;O (MMIO)&lt;&#x2F;strong&gt;
A scheme where hardware device registers are assigned addresses in the same address space as system memory. The CPU accesses device registers using the same load and store instructions it uses for RAM. The chipset routes the transaction to the correct bus based on the address.
&lt;&#x2F;div&gt;
&lt;p&gt;From the CPU&#x27;s perspective, the address space is one big range of numbers. Some ranges map to RAM. Other ranges map to PCIe devices. The chipset and root complex route each memory access to the right destination based on address ranges configured during enumeration. The firmware sets up these mappings; the OS can adjust them later.&lt;&#x2F;p&gt;
&lt;p&gt;This is why a 32-bit system with 4 GB of RAM might only report 3.2 GB available. The missing 800 MB of address space is reserved for MMIO -- GPU frame buffers, device registers, and the firmware itself. On 64-bit systems, MMIO regions are typically mapped above the 4 GB line, so all physical RAM is accessible.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The firmware enumerates every bus and assigns every device an address range before the operating system loads. The OS inherits this map and can modify it, but the initial discovery is the firmware&#x27;s job. Without enumeration, the OS would have no idea what hardware is present.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;usb-a-different-model&quot;&gt;USB: A Different Model&lt;&#x2F;h2&gt;
&lt;p&gt;USB (Universal Serial Bus) takes a different approach from PCIe. Where PCIe devices are discovered by scanning a static tree of addresses, USB devices announce themselves when they are plugged in. The USB host controller detects a voltage change on the port, then initiates a conversation with the new device to learn its type and capabilities.&lt;&#x2F;p&gt;
&lt;p&gt;USB is also hierarchical. A host controller connects to a root hub. The root hub has ports. External hubs can be connected to those ports, creating a tree up to seven levels deep with up to 127 devices. Each device gets a dynamic address assigned by the host controller during enumeration.&lt;&#x2F;p&gt;
&lt;p&gt;The firmware needs USB working early for a practical reason: keyboards and mice. If you want to enter the firmware setup screen or select a boot device, the firmware must have a USB driver running. UEFI firmware includes USB drivers as part of its DXE phase; BIOS implementations had to include USB support in their interrupt service routines.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sata-and-storage-buses&quot;&gt;SATA and Storage Buses&lt;&#x2F;h2&gt;
&lt;p&gt;SATA (Serial ATA) connects traditional hard drives and older SSDs. Like PCIe, it uses serial point-to-point links, but it has a simpler protocol optimized for block storage. Each SATA port connects to exactly one device. The SATA controller typically lives on the chipset and presents itself to the firmware as a PCIe device.&lt;&#x2F;p&gt;
&lt;p&gt;Modern NVMe SSDs bypass SATA entirely. They connect directly via PCIe, which gives them access to the full PCIe bandwidth and a much simpler command protocol. A SATA SSD maxes out at about 550 MB&#x2F;s. An NVMe SSD on PCIe 4.0 x4 can reach 7,000 MB&#x2F;s. The difference is not just speed -- NVMe supports 65,535 command queues compared to SATA&#x27;s single queue, which matters enormously for parallel workloads.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 06c -- Storage bus bandwidth comparison&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 240&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;240&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Storage Interface Bandwidth&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Bars --&gt;
  &lt;!-- SATA III --&gt;
&lt;p&gt;&lt;text x=&quot;120&quot; y=&quot;65&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;SATA III&lt;&#x2F;text&gt;
&lt;rect x=&quot;130&quot; y=&quot;50&quot; width=&quot;26&quot; height=&quot;25&quot; rx=&quot;2&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
&lt;text x=&quot;165&quot; y=&quot;67&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;0.6 GB&#x2F;s&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- NVMe PCIe 3.0 x4 --&gt;
&lt;p&gt;&lt;text x=&quot;120&quot; y=&quot;105&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;NVMe PCIe 3.0&lt;&#x2F;text&gt;
&lt;rect x=&quot;130&quot; y=&quot;90&quot; width=&quot;150&quot; height=&quot;25&quot; rx=&quot;2&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
&lt;text x=&quot;290&quot; y=&quot;107&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;3.5 GB&#x2F;s&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- NVMe PCIe 4.0 x4 --&gt;
&lt;p&gt;&lt;text x=&quot;120&quot; y=&quot;145&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;NVMe PCIe 4.0&lt;&#x2F;text&gt;
&lt;rect x=&quot;130&quot; y=&quot;130&quot; width=&quot;300&quot; height=&quot;25&quot; rx=&quot;2&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
&lt;text x=&quot;440&quot; y=&quot;147&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;7.0 GB&#x2F;s&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- NVMe PCIe 5.0 x4 --&gt;
&lt;p&gt;&lt;text x=&quot;120&quot; y=&quot;185&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;NVMe PCIe 5.0&lt;&#x2F;text&gt;
&lt;rect x=&quot;130&quot; y=&quot;170&quot; width=&quot;420&quot; height=&quot;25&quot; rx=&quot;2&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
&lt;text x=&quot;425&quot; y=&quot;187&quot; fill=&quot;#35383C&quot; font-size=&quot;10&quot;&gt;14.0 GB&#x2F;s&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Scale line --&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;210&quot; x2=&quot;550&quot; y2=&quot;210&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;225&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;start&quot;&gt;0&lt;&#x2F;text&gt;
  &lt;text x=&quot;340&quot; y=&quot;225&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;7 GB&#x2F;s&lt;&#x2F;text&gt;
  &lt;text x=&quot;550&quot; y=&quot;225&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;14 GB&#x2F;s&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Each generation of PCIe roughly doubles the bandwidth available to storage. NVMe SSDs on PCIe 5.0 are more than 20 times faster than a SATA III drive.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;dma-letting-devices-access-memory-directly&quot;&gt;DMA: Letting Devices Access Memory Directly&lt;&#x2F;h2&gt;
&lt;p&gt;Normally, data moves through the CPU: the CPU reads from the device, then writes to memory, or vice versa. This works but wastes CPU cycles on what is essentially a copy operation.&lt;&#x2F;p&gt;
&lt;p&gt;DMA -- Direct Memory Access -- lets devices read from and write to system memory without involving the CPU at all. A network adapter receiving a packet can write the data directly into a buffer in RAM, then interrupt the CPU to say &quot;your data is ready.&quot; The CPU never touches the data during the transfer.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: DMA (Direct Memory Access)&lt;&#x2F;strong&gt;
A capability that allows hardware devices to transfer data directly to or from system memory without CPU involvement. The device is given a memory address and a length, and it handles the transfer autonomously. The CPU is free to do other work during the transfer.
&lt;&#x2F;div&gt;
&lt;p&gt;DMA is essential for high-throughput devices. A PCIe 4.0 NVMe drive can push 7 GB&#x2F;s. If the CPU had to mediate every byte of that transfer, it would spend most of its time just copying data. DMA lets the drive write directly to RAM while the CPU runs application code.&lt;&#x2F;p&gt;
&lt;p&gt;The security implication is significant. A device with DMA access can read any physical memory address. A malicious PCIe device -- or a compromised firmware on a legitimate device -- could read encryption keys, passwords, or any other data in RAM. This is why modern systems include an IOMMU (Input&#x2F;Output Memory Management Unit) that restricts which memory regions each device can access. The IOMMU is configured by the firmware and managed by the OS.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The bus system is the circulatory system of the computer. PCIe provides the high-bandwidth backbone, USB handles human-interface and peripheral devices, and SATA connects traditional storage. The firmware discovers all of these during enumeration, assigns addresses, and builds the device map that the operating system will inherit. DMA lets devices move data without burdening the CPU, but it requires careful access control.
&lt;&#x2F;div&gt;
&lt;p&gt;With memory working and the bus system enumerated, the firmware knows what hardware is available. The next step is finding something to boot from.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;07-finding-the-boot-device&#x2F;&quot;&gt;Finding the Boot Device&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Memory Initialization</title>
        <published>2025-01-07T00:00:00+00:00</published>
        <updated>2025-01-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/05-memory-initialization/"/>
        <id>https://t34ch.tech/coldboot/articles/05-memory-initialization/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/05-memory-initialization/">&lt;p&gt;When you press the power button, the processor wakes up and starts executing firmware from flash memory. But there is a problem: the system&#x27;s main memory -- the DRAM installed in those slots on the motherboard -- does not work yet. It is not broken. It simply has not been configured.&lt;&#x2F;p&gt;
&lt;p&gt;This is one of the least understood parts of the boot process. The CPU needs memory to run software, but configuring memory requires running software. The firmware has to solve this chicken-and-egg problem before anything else can happen.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-ram-does-not-just-work&quot;&gt;Why RAM Does Not Just Work&lt;&#x2F;h2&gt;
&lt;p&gt;A stick of RAM is not a simple storage device. It is a dense grid of capacitors and transistors organized into rows and columns across multiple internal banks. Each capacitor holds one bit of data as an electrical charge. Reading or writing any bit requires activating the correct row, waiting for the signals to stabilize, then selecting the correct column.&lt;&#x2F;p&gt;
&lt;p&gt;The timing of every one of these operations matters. How long the row signal must be held before the data is valid. How many clock cycles must elapse between activating one row and activating another. How frequently each row must be refreshed before the capacitors leak their charge. These timings are measured in clock cycles and nanoseconds, and they vary between manufacturers, speeds, and even production batches.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: DRAM (Dynamic Random-Access Memory)&lt;&#x2F;strong&gt;
The main system memory in virtually all computers. &quot;Dynamic&quot; means each bit is stored as a charge on a tiny capacitor that must be periodically refreshed -- re-read and re-written -- or the data disappears. This is in contrast to SRAM (Static RAM), which holds its state without refreshing but uses more transistors per bit.
&lt;&#x2F;div&gt;
&lt;p&gt;If the memory controller sends commands with the wrong timing, the data that comes back is garbage. Worse, incorrect timings can cause electrical stress that damages the memory chips over time. The firmware must discover the correct timings for the specific memory modules installed, then program the memory controller to use them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;spd-the-memory-s-identity-card&quot;&gt;SPD: The Memory&#x27;s Identity Card&lt;&#x2F;h2&gt;
&lt;p&gt;Every DDR memory module carries a small chip called an SPD EEPROM. SPD stands for Serial Presence Detect. This chip stores a data sheet about the module: its capacity, the number of ranks, the supported clock speeds, and a table of timing parameters specified by JEDEC -- the standards body that defines how DDR memory works.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: SPD (Serial Presence Detect)&lt;&#x2F;strong&gt;
A small read-only memory chip on each DRAM module that stores the module&#x27;s specifications. The firmware reads SPD data over a simple two-wire bus (SMBus or I2C) to learn what memory is installed and what timings it supports.
&lt;&#x2F;div&gt;
&lt;p&gt;The firmware reads SPD data at a very early stage, using a simple serial protocol called SMBus (System Management Bus). This bus works even before the main memory controller is configured because it runs on a separate, low-speed interface. Think of it as asking the memory stick to introduce itself before you try to have a conversation.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 05a -- SPD data read from a DDR module&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- DIMM module representation --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;30&quot; width=&quot;240&quot; height=&quot;80&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;150&quot; y=&quot;55&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;DDR Memory Module&lt;&#x2F;text&gt;
  &lt;text x=&quot;150&quot; y=&quot;75&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;DRAM chips + SPD EEPROM&lt;&#x2F;text&gt;
  &lt;text x=&quot;150&quot; y=&quot;95&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;8 GB DDR4-3200&lt;&#x2F;text&gt;
  &lt;!-- SPD chip detail --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;125&quot; width=&quot;60&quot; height=&quot;35&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;147&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;SPD&lt;&#x2F;text&gt;
  &lt;!-- SMBus line --&gt;
  &lt;line x1=&quot;110&quot; y1=&quot;142&quot; x2=&quot;300&quot; y2=&quot;142&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; stroke-dasharray=&quot;6,3&quot;&#x2F;&gt;
  &lt;text x=&quot;205&quot; y=&quot;135&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;SMBus (I2C)&lt;&#x2F;text&gt;
  &lt;!-- Firmware&#x2F;CPU --&gt;
  &lt;rect x=&quot;300&quot; y=&quot;125&quot; width=&quot;120&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;360&quot; y=&quot;147&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Firmware (PEI)&lt;&#x2F;text&gt;
  &lt;!-- SPD data fields --&gt;
  &lt;rect x=&quot;310&quot; y=&quot;185&quot; width=&quot;240&quot; height=&quot;80&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;430&quot; y=&quot;205&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;SPD Data Contents&lt;&#x2F;text&gt;
  &lt;text x=&quot;330&quot; y=&quot;225&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Module type:  DDR4 UDIMM&lt;&#x2F;text&gt;
  &lt;text x=&quot;330&quot; y=&quot;240&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Capacity:     8 GB, 1 rank&lt;&#x2F;text&gt;
  &lt;text x=&quot;330&quot; y=&quot;255&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Speed:        3200 MT&#x2F;s&lt;&#x2F;text&gt;
  &lt;rect x=&quot;30&quot; y=&quot;185&quot; width=&quot;240&quot; height=&quot;80&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;150&quot; y=&quot;205&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;JEDEC Timings&lt;&#x2F;text&gt;
  &lt;text x=&quot;50&quot; y=&quot;225&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;tCL  = 22    (CAS latency)&lt;&#x2F;text&gt;
  &lt;text x=&quot;50&quot; y=&quot;240&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;tRCD = 22    (row-to-column)&lt;&#x2F;text&gt;
  &lt;text x=&quot;50&quot; y=&quot;255&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;tRP  = 22    (row precharge)&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The firmware reads identity and timing data from the SPD chip over a slow serial bus before the main memory interface is usable.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The SPD data includes JEDEC-standard timing parameters. You may have seen these on memory packaging as numbers like &quot;22-22-22-52.&quot; Those four numbers represent CAS latency (tCL), row-to-column delay (tRCD), row precharge time (tRP), and row active time (tRAS), all measured in clock cycles. They tell the memory controller the minimum number of cycles it must wait between each type of operation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;memory-training-the-calibration-process&quot;&gt;Memory Training: The Calibration Process&lt;&#x2F;h2&gt;
&lt;p&gt;Reading the SPD data tells the firmware what the memory modules are. But it does not tell the firmware how the signals actually behave on this specific motherboard, with this specific CPU, at the current temperature, with these specific trace lengths on the circuit board.&lt;&#x2F;p&gt;
&lt;p&gt;Electrical signals take time to travel along the copper traces between the CPU and the memory slots. The length of each trace is slightly different. The impedance varies with temperature. At DDR4 and DDR5 data rates -- billions of transfers per second -- even a fraction of a nanosecond of misalignment between the clock signal and the data signals will corrupt data.&lt;&#x2F;p&gt;
&lt;p&gt;This is why the firmware must &quot;train&quot; the memory. Training is a calibration process where the firmware writes known patterns to memory, reads them back, and adjusts the timing parameters until the reads return correct data consistently. It is like tuning a radio dial: you sweep through the range, find the sweet spot where the signal is clearest, then lock it in.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 05b -- Memory training: finding the timing window&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;DQS&#x2F;DQ Eye Diagram (simplified)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Axes --&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;60&quot; x2=&quot;60&quot; y2=&quot;240&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;240&quot; x2=&quot;540&quot; y2=&quot;240&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;260&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;TIMING OFFSET (ps)&lt;&#x2F;text&gt;
  &lt;text x=&quot;30&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot; transform=&quot;rotate(-90 30 150)&quot;&gt;VOLTAGE&lt;&#x2F;text&gt;
  &lt;!-- Eye opening shape --&gt;
  &lt;path d=&quot;M 120,150 Q 200,60 300,60 Q 400,60 480,150&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2.5&quot;&#x2F;&gt;
  &lt;path d=&quot;M 120,150 Q 200,240 300,240 Q 400,240 480,150&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2.5&quot;&#x2F;&gt;
  &lt;!-- Fail zones (left and right) --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;60&quot; width=&quot;60&quot; height=&quot;180&quot; fill=&quot;rgba(192,57,43,0.15)&quot;&#x2F;&gt;
  &lt;rect x=&quot;480&quot; y=&quot;60&quot; width=&quot;60&quot; height=&quot;180&quot; fill=&quot;rgba(192,57,43,0.15)&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;155&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;FAIL&lt;&#x2F;text&gt;
  &lt;text x=&quot;510&quot; y=&quot;155&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;FAIL&lt;&#x2F;text&gt;
  &lt;!-- Pass zone --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;90&quot; width=&quot;160&quot; height=&quot;120&quot; fill=&quot;rgba(57,211,83,0.1)&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;155&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;PASS&lt;&#x2F;text&gt;
  &lt;text x=&quot;300&quot; y=&quot;172&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;(timing eye)&lt;&#x2F;text&gt;
  &lt;!-- Center point marker --&gt;
  &lt;circle cx=&quot;300&quot; cy=&quot;150&quot; r=&quot;5&quot; fill=&quot;#FFD700&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;300&quot; y1=&quot;90&quot; x2=&quot;300&quot; y2=&quot;210&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;225&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;optimal sample point&lt;&#x2F;text&gt;
  &lt;!-- Sweep arrows --&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;280&quot; x2=&quot;460&quot; y2=&quot;280&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowOr05)&quot;&#x2F;&gt;
  &lt;line x1=&quot;460&quot; y1=&quot;280&quot; x2=&quot;140&quot; y2=&quot;280&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-start=&quot;url(#arrowOr05b)&quot;&#x2F;&gt;
  &lt;text x=&quot;300&quot; y=&quot;295&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;firmware sweeps delay values&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrowOr05&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;10&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arrowOr05b&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;0&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 10 0 L 0 5 L 10 10 z&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The firmware sweeps through possible timing offsets, looking for the window where data reads back correctly. It then sets the sample point in the center of that window for maximum reliability.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Training involves multiple phases. Write leveling adjusts the timing of write commands to each DRAM chip individually. Read leveling does the same for reads. Gate training determines the exact moment to start capturing data from the bus. Each phase runs independently for each byte lane -- each group of eight data pins -- because the trace lengths differ.&lt;&#x2F;p&gt;
&lt;p&gt;The entire process can take hundreds of milliseconds. That does not sound like much, but remember: this happens before the system has usable memory. The firmware runs the training code from the CPU&#x27;s internal cache, which is repurposed as temporary RAM. This technique is called Cache-as-RAM, or CAR.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Cache-as-RAM (CAR)&lt;&#x2F;strong&gt;
A technique where the CPU&#x27;s L1 or L2 cache is configured as a small block of read&#x2F;write memory. This gives the firmware a few hundred kilobytes to work with -- enough to run the memory training algorithm -- before DRAM is available. Intel calls this mode &quot;No-Eviction Mode.&quot;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-memory-controller&quot;&gt;The Memory Controller&lt;&#x2F;h2&gt;
&lt;p&gt;The component responsible for sending correctly-timed commands to the DRAM is the memory controller. In modern systems, the memory controller is built directly into the CPU die. Older systems had it in a separate chip called the northbridge.&lt;&#x2F;p&gt;
&lt;p&gt;The memory controller does several things. It translates memory addresses from the CPU into the bank, row, and column addresses that the DRAM chips understand. It schedules commands to maximize throughput -- reordering reads and writes to avoid unnecessary row activations. It manages the refresh cycle, periodically re-reading and re-writing every row so the capacitors do not lose their charge.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 05c -- Memory controller and DRAM organization&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 320&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;320&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- CPU --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;100&quot; width=&quot;120&quot; height=&quot;120&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;135&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;CPU&lt;&#x2F;text&gt;
  &lt;rect x=&quot;35&quot; y=&quot;150&quot; width=&quot;90&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;172&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Memory&lt;&#x2F;text&gt;
  &lt;text x=&quot;80&quot; y=&quot;187&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Controller&lt;&#x2F;text&gt;
  &lt;!-- Bus lines --&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;155&quot; x2=&quot;210&quot; y2=&quot;155&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;170&quot; x2=&quot;210&quot; y2=&quot;170&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;line x1=&quot;140&quot; y1=&quot;185&quot; x2=&quot;210&quot; y2=&quot;185&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
&lt;p&gt;&lt;text x=&quot;175&quot; y=&quot;148&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;CMD&#x2F;ADDR&lt;&#x2F;text&gt;
&lt;text x=&quot;175&quot; y=&quot;167&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;DATA (DQ)&lt;&#x2F;text&gt;
&lt;text x=&quot;175&quot; y=&quot;198&quot; fill=&quot;#00BFFF&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;CLOCK&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Channel label --&gt;
&lt;p&gt;&lt;text x=&quot;175&quot; y=&quot;230&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;DDR channel&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- DIMM --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;40&quot; width=&quot;350&quot; height=&quot;260&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;385&quot; y=&quot;30&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;DRAM Module (1 DIMM)&lt;&#x2F;text&gt;
  &lt;!-- Banks --&gt;
  &lt;rect x=&quot;230&quot; y=&quot;60&quot; width=&quot;75&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;267&quot; y=&quot;80&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bank 0&lt;&#x2F;text&gt;
  &lt;text x=&quot;267&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;rows x cols&lt;&#x2F;text&gt;
  &lt;rect x=&quot;315&quot; y=&quot;60&quot; width=&quot;75&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;352&quot; y=&quot;80&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bank 1&lt;&#x2F;text&gt;
  &lt;text x=&quot;352&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;rows x cols&lt;&#x2F;text&gt;
  &lt;rect x=&quot;400&quot; y=&quot;60&quot; width=&quot;75&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;437&quot; y=&quot;80&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Bank 2&lt;&#x2F;text&gt;
  &lt;text x=&quot;437&quot; y=&quot;100&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;rows x cols&lt;&#x2F;text&gt;
  &lt;rect x=&quot;485&quot; y=&quot;60&quot; width=&quot;55&quot; height=&quot;55&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;512&quot; y=&quot;92&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;...&lt;&#x2F;text&gt;
  &lt;!-- Row&#x2F;Column detail --&gt;
  &lt;rect x=&quot;230&quot; y=&quot;135&quot; width=&quot;310&quot; height=&quot;80&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;385&quot; y=&quot;155&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Access Sequence&lt;&#x2F;text&gt;
  &lt;text x=&quot;250&quot; y=&quot;175&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;1. Activate row  (tRCD wait)&lt;&#x2F;text&gt;
  &lt;text x=&quot;250&quot; y=&quot;192&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;2. Read column   (tCL wait)&lt;&#x2F;text&gt;
  &lt;text x=&quot;250&quot; y=&quot;209&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;3. Precharge     (tRP wait)&lt;&#x2F;text&gt;
  &lt;!-- Refresh note --&gt;
  &lt;rect x=&quot;230&quot; y=&quot;230&quot; width=&quot;310&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#35383C&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;385&quot; y=&quot;250&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Refresh: every row re-read every 64 ms&lt;&#x2F;text&gt;
  &lt;text x=&quot;385&quot; y=&quot;268&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Miss a refresh cycle and data silently corrupts&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The memory controller on the CPU translates addresses into bank&#x2F;row&#x2F;column commands. Each access follows a strict sequence of timed operations. Refresh runs continuously in the background.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;After training completes, the firmware programs all the calibrated timing values into the memory controller&#x27;s configuration registers. From this point forward, the CPU can read and write main memory normally. The training results are often saved to flash storage so that the next boot can reuse them, making subsequent boots faster. This is why changing or rearranging your RAM sticks sometimes triggers a longer boot -- the firmware detects the change and retrains from scratch.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ddr-generations&quot;&gt;DDR Generations&lt;&#x2F;h2&gt;
&lt;p&gt;The DDR standard has gone through several generations. Each generation roughly doubles the data transfer rate and reduces power consumption while increasing complexity.&lt;&#x2F;p&gt;
&lt;p&gt;DDR3 ran at 800 to 1066 MHz base clock with a peak transfer rate around 17 GB&#x2F;s per channel. DDR4 pushed that to 1200-1600 MHz base, adding bank groups and finer timing granularity. DDR5, the current generation, doubled the channel width by splitting each module into two independent 32-bit channels, added on-die ECC (error correction within each chip), and moved the voltage regulator from the motherboard onto the module itself.&lt;&#x2F;p&gt;
&lt;p&gt;Each generation requires a different training algorithm. The firmware for a DDR5 system is substantially more complex than for DDR4 because DDR5 has more timing parameters, more per-bit adjustments, and the two-channel-per-DIMM architecture that requires independent calibration of each sub-channel.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
RAM does not work at power-on. The firmware must read each module&#x27;s SPD data, run a training algorithm that sweeps through timing parameters to find the reliable operating window, and program the memory controller with the results. Only then does the system have usable main memory. Everything before this point runs from flash or CPU cache.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;dual-channel-and-interleaving&quot;&gt;Dual Channel and Interleaving&lt;&#x2F;h2&gt;
&lt;p&gt;Most consumer systems support two memory channels -- two independent paths between the CPU and the DRAM. When you install matching modules in both channels, the memory controller can interleave accesses: it sends even-addressed cache lines to one channel and odd-addressed cache lines to the other, effectively doubling the available bandwidth.&lt;&#x2F;p&gt;
&lt;p&gt;This is why memory kits are sold in pairs. Two 8 GB modules in dual channel will outperform a single 16 GB module in most workloads, even though the total capacity is the same. The firmware detects the channel configuration during training and enables interleaving automatically when the modules match.&lt;&#x2F;p&gt;
&lt;p&gt;Server systems take this further. A dual-socket server might have eight or twelve memory channels per processor, with multiple DIMMs per channel. The firmware must train every module on every channel, which is why enterprise servers often take noticeably longer to boot than desktops.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ecc-when-bits-flip&quot;&gt;ECC: When Bits Flip&lt;&#x2F;h2&gt;
&lt;p&gt;Cosmic rays, alpha particles from chip packaging, and electrical noise can flip bits in DRAM. In a desktop, a flipped bit might crash an application or corrupt a file. In a server, it could corrupt a database or crash a hypervisor managing hundreds of virtual machines.&lt;&#x2F;p&gt;
&lt;p&gt;ECC memory -- Error-Correcting Code memory -- adds extra data bits to each word. For every 64 bits of data, ECC adds 8 bits of parity information. This allows the memory controller to detect and correct any single-bit error, and detect (but not correct) any two-bit error.&lt;&#x2F;p&gt;
&lt;p&gt;ECC requires support in the memory controller, the DRAM modules, and the firmware. The training process for ECC memory is slightly longer because the error-correction logic must also be calibrated. Consumer platforms often do not support ECC, while server and workstation platforms require it.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Memory initialization is one of the most time-consuming parts of the boot process and one of the most critical. Without trained, working DRAM, the system has nothing but a few hundred kilobytes of cache to work with. Everything that follows -- loading the bootloader, decompressing the kernel, building the page tables -- depends on the memory controller being correctly configured during this early phase.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-happens-next&quot;&gt;What Happens Next&lt;&#x2F;h2&gt;
&lt;p&gt;Once memory training completes, the firmware copies itself from the cramped cache-as-RAM environment into proper DRAM and continues execution with megabytes of memory available. The next task is discovering all the other hardware in the system: storage controllers, network adapters, USB hubs, and graphics cards. That discovery happens through the bus system.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;06-the-bus-system&#x2F;&quot;&gt;The Bus System&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>UEFI vs Legacy BIOS</title>
        <published>2025-01-06T00:00:00+00:00</published>
        <updated>2025-01-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/04-uefi-vs-legacy-bios/"/>
        <id>https://t34ch.tech/coldboot/articles/04-uefi-vs-legacy-bios/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/04-uefi-vs-legacy-bios/">&lt;p&gt;The firmware is the first software that runs when you press the power button. For decades, that software was BIOS. Then a replacement arrived called UEFI. Most computers sold today use UEFI, but the older system is still everywhere -- in virtual machines, embedded devices, and the assumptions baked into millions of lines of existing code.&lt;&#x2F;p&gt;
&lt;p&gt;Understanding both systems is not optional. You will encounter both, and the differences between them shape everything from disk layout to operating system security.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-original-bios&quot;&gt;The Original BIOS&lt;&#x2F;h2&gt;
&lt;p&gt;BIOS stands for Basic Input&#x2F;Output System. IBM introduced it with the original PC in 1981. Its job was straightforward: test the hardware, find a disk with a boot program on it, load that program into memory, and hand over control.&lt;&#x2F;p&gt;
&lt;p&gt;The original BIOS ran in 16-bit real mode -- the same mode the Intel 8088 processor started in. It could address one megabyte of memory. It used interrupt-based service routines that an operating system could call to read a disk sector or write a character to the screen. The interface was simple, stable, and wildly successful.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Real mode&lt;&#x2F;strong&gt;
The processor mode that all x86 CPUs start in. It uses 16-bit registers and can address only 1 MB of memory. Every x86 chip, even a modern 64-bit processor, wakes up in this mode for backward compatibility.
&lt;&#x2F;div&gt;
&lt;p&gt;For twenty years, BIOS barely changed. Vendors added features -- boot menus, PCI scanning, ACPI tables -- but the core interface remained 16-bit, interrupt-driven, and limited to 1 MB of addressable memory. The disk layout it used, called MBR, capped out at 2 terabytes. By the early 2000s, these limits were becoming painful.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-bios-had-to-go&quot;&gt;Why BIOS Had to Go&lt;&#x2F;h2&gt;
&lt;p&gt;Three problems forced the industry to act.&lt;&#x2F;p&gt;
&lt;p&gt;First, the 2 TB disk limit. MBR partition tables use 32-bit logical block addresses. With 512-byte sectors, that gives you 2^32 times 512 bytes -- exactly 2 TiB. Server vendors were already shipping disks larger than that.&lt;&#x2F;p&gt;
&lt;p&gt;Second, the 1 MB memory ceiling. BIOS code had to run in real mode or use awkward workarounds to access more memory. Writing firmware in 16-bit assembly was slow, error-prone, and hostile to features like network stacks or graphical setup screens.&lt;&#x2F;p&gt;
&lt;p&gt;Third, security. BIOS had no mechanism to verify that the code it loaded from disk was legitimate. Any program written to the first sector of a disk would be executed without question. Rootkits that replaced the boot sector were a real and growing threat.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 04a -- BIOS limitations at a glance&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 260&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;260&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Title row --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;30&quot; fill=&quot;#FFD700&quot; font-size=&quot;14&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Legacy BIOS Constraints&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Three columns --&gt;
  &lt;!-- Memory --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;50&quot; width=&quot;160&quot; height=&quot;180&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;110&quot; y=&quot;75&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Memory&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;105&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;28&quot; text-anchor=&quot;middle&quot;&gt;1 MB&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;130&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;16-bit real mode&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;20-bit address bus&lt;&#x2F;text&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;170&quot; x2=&quot;160&quot; y2=&quot;170&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;110&quot; y=&quot;195&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;No protected mode&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;215&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;firmware access&lt;&#x2F;text&gt;
  &lt;!-- Disk --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;50&quot; width=&quot;160&quot; height=&quot;180&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;75&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Disk&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;105&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;28&quot; text-anchor=&quot;middle&quot;&gt;2 TiB&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;130&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;32-bit LBA in MBR&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;512-byte sectors&lt;&#x2F;text&gt;
  &lt;line x1=&quot;240&quot; y1=&quot;170&quot; x2=&quot;340&quot; y2=&quot;170&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;195&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;4 primary partitions&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;215&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;maximum&lt;&#x2F;text&gt;
  &lt;!-- Security --&gt;
  &lt;rect x=&quot;390&quot; y=&quot;50&quot; width=&quot;160&quot; height=&quot;180&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;470&quot; y=&quot;75&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Security&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;105&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;28&quot; text-anchor=&quot;middle&quot;&gt;None&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;130&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;No code signing&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;No verification&lt;&#x2F;text&gt;
  &lt;line x1=&quot;420&quot; y1=&quot;170&quot; x2=&quot;520&quot; y2=&quot;170&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;470&quot; y=&quot;195&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Any sector 0 code&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;215&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;runs unchecked&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The three hard limits that made BIOS replacement inevitable: memory, disk size, and security.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;enter-uefi&quot;&gt;Enter UEFI&lt;&#x2F;h2&gt;
&lt;p&gt;UEFI stands for Unified Extensible Firmware Interface. Intel started the project in the mid-1990s under the name EFI for their Itanium processor, which had no legacy BIOS at all. The specification went through several revisions before being handed to an industry consortium called the UEFI Forum in 2005. Today, UEFI is the standard firmware interface for virtually all x86 and ARM platforms.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: UEFI (Unified Extensible Firmware Interface)&lt;&#x2F;strong&gt;
A specification that defines the interface between a computer&#x27;s firmware and its operating system. Unlike BIOS, UEFI runs in 32-bit or 64-bit mode, can address all of system memory, and includes a driver model, a shell, and a boot manager.
&lt;&#x2F;div&gt;
&lt;p&gt;UEFI is not a single piece of software. It is a specification -- a contract that describes how firmware should behave, what services it must provide, and how operating systems should interact with it. Different vendors write their own UEFI implementations. What they share is the interface.&lt;&#x2F;p&gt;
&lt;p&gt;The practical differences from BIOS are large. UEFI firmware runs in 32-bit or 64-bit protected mode from the start. It can address gigabytes of memory. It has a built-in boot manager that understands file systems, so it can load a boot program from a specific file path on a specific partition rather than blindly executing whatever sits in the first disk sector. It supports a driver model, a network stack, and a command-line shell -- all before the operating system loads.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gpt-the-new-partition-table&quot;&gt;GPT: The New Partition Table&lt;&#x2F;h2&gt;
&lt;p&gt;UEFI introduced a new disk layout called GPT -- the GUID Partition Table. Where MBR uses 32-bit addresses and supports four primary partitions, GPT uses 64-bit addresses and supports up to 128 partitions by default.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 04b -- MBR vs GPT disk layout&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- MBR layout --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;25&quot; fill=&quot;#FF6600&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;MBR Layout&lt;&#x2F;text&gt;
&lt;rect x=&quot;30&quot; y=&quot;40&quot; width=&quot;70&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
&lt;text x=&quot;65&quot; y=&quot;60&quot; fill=&quot;#FF6600&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Boot Code&lt;&#x2F;text&gt;
&lt;text x=&quot;65&quot; y=&quot;75&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;446 bytes&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;105&quot; y=&quot;40&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;60&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Partition Table&lt;&#x2F;text&gt;
  &lt;text x=&quot;160&quot; y=&quot;75&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;4 entries x 16B&lt;&#x2F;text&gt;
  &lt;rect x=&quot;220&quot; y=&quot;40&quot; width=&quot;30&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;68&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;Sig&lt;&#x2F;text&gt;
  &lt;rect x=&quot;270&quot; y=&quot;40&quot; width=&quot;90&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;315&quot; y=&quot;68&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Partition 1&lt;&#x2F;text&gt;
  &lt;rect x=&quot;365&quot; y=&quot;40&quot; width=&quot;90&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;68&quot; fill=&quot;#39D353&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Partition 2&lt;&#x2F;text&gt;
  &lt;rect x=&quot;460&quot; y=&quot;40&quot; width=&quot;90&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;505&quot; y=&quot;68&quot; fill=&quot;#8C9097&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;...&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;115&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Sector 0 (512 bytes) holds EVERYTHING: code + table + signature&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- GPT layout --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;155&quot; fill=&quot;#00BFFF&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;GPT Layout&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;30&quot; y=&quot;170&quot; width=&quot;60&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;60&quot; y=&quot;190&quot; fill=&quot;#FF6600&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;Protective&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;202&quot; fill=&quot;#FF6600&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;MBR&lt;&#x2F;text&gt;
  &lt;rect x=&quot;95&quot; y=&quot;170&quot; width=&quot;70&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;130&quot; y=&quot;190&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;GPT Header&lt;&#x2F;text&gt;
  &lt;text x=&quot;130&quot; y=&quot;202&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;LBA 1&lt;&#x2F;text&gt;
  &lt;rect x=&quot;170&quot; y=&quot;170&quot; width=&quot;120&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;230&quot; y=&quot;190&quot; fill=&quot;#FFD700&quot; font-size=&quot;9&quot; text-anchor=&quot;middle&quot;&gt;Partition Entries&lt;&#x2F;text&gt;
  &lt;text x=&quot;230&quot; y=&quot;202&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;128 entries&lt;&#x2F;text&gt;
  &lt;rect x=&quot;295&quot; y=&quot;170&quot; width=&quot;150&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;370&quot; y=&quot;198&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Partitions ...&lt;&#x2F;text&gt;
  &lt;rect x=&quot;450&quot; y=&quot;170&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;500&quot; y=&quot;190&quot; fill=&quot;#00BFFF&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;Backup GPT&lt;&#x2F;text&gt;
  &lt;text x=&quot;500&quot; y=&quot;202&quot; fill=&quot;#8C9097&quot; font-size=&quot;8&quot; text-anchor=&quot;middle&quot;&gt;Header+Entries&lt;&#x2F;text&gt;
  &lt;!-- Arrows showing backup --&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;225&quot; x2=&quot;130&quot; y2=&quot;260&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;500&quot; y1=&quot;225&quot; x2=&quot;500&quot; y2=&quot;260&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;260&quot; x2=&quot;500&quot; y2=&quot;260&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;3,3&quot;&#x2F;&gt;
  &lt;text x=&quot;315&quot; y=&quot;275&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Backup copy at end of disk = redundancy&lt;&#x2F;text&gt;
  &lt;!-- Comparison --&gt;
&lt;p&gt;&lt;text x=&quot;145&quot; y=&quot;315&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;MBR: 4 partitions, 2 TiB max&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;315&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;GPT: 128 partitions, 9.4 ZB max&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;MBR crams everything into a single 512-byte sector. GPT spreads the metadata across multiple sectors and keeps a backup copy at the end of the disk.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The first sector of a GPT disk contains a &quot;protective MBR&quot; -- a fake MBR entry that marks the entire disk as a single partition of an unknown type. This prevents old MBR-only tools from misinterpreting the disk as empty and overwriting the GPT data. It is a compatibility shim, nothing more.&lt;&#x2F;p&gt;
&lt;p&gt;Each GPT partition entry includes a 128-bit GUID (Globally Unique Identifier) as its type code and another GUID as its unique partition identifier. The operating system uses these GUIDs to identify partitions reliably, without depending on partition order or drive letters.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-efi-system-partition&quot;&gt;The EFI System Partition&lt;&#x2F;h3&gt;
&lt;p&gt;UEFI-booted systems have a small FAT32 partition called the EFI System Partition, or ESP. This is where the firmware looks for bootloader programs. The ESP typically sits at the beginning of the disk and is between 100 MB and 550 MB in size.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: EFI System Partition (ESP)&lt;&#x2F;strong&gt;
A FAT32-formatted partition with a specific GPT type GUID that UEFI firmware knows how to read. It contains bootloader executables, firmware updates, and other files the firmware needs before the operating system loads.
&lt;&#x2F;div&gt;
&lt;p&gt;Inside the ESP, bootloaders live at well-known paths. For example, the default fallback path is &lt;code&gt;\EFI\BOOT\BOOTX64.EFI&lt;&#x2F;code&gt; on a 64-bit x86 system. A Linux distribution might install its bootloader at &lt;code&gt;\EFI\ubuntu\shimx64.efi&lt;&#x2F;code&gt;. The UEFI boot manager stores these paths in NVRAM variables and presents them as boot options.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-uefi-boot-flow&quot;&gt;The UEFI Boot Flow&lt;&#x2F;h2&gt;
&lt;p&gt;The boot process under UEFI looks different from BIOS. Instead of loading a 512-byte sector and jumping to it, UEFI firmware reads a full executable file from the ESP.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 04c -- UEFI boot flow vs BIOS boot flow&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 380&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;380&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- BIOS flow --&gt;
&lt;p&gt;&lt;text x=&quot;145&quot; y=&quot;25&quot; fill=&quot;#FF6600&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;Legacy BIOS&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;50&quot; y=&quot;40&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;62&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;POST (hardware test)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;75&quot; x2=&quot;145&quot; y2=&quot;95&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowOrange)&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;95&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;117&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Load MBR sector 0&lt;&#x2F;text&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;130&quot; x2=&quot;145&quot; y2=&quot;150&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowOrange)&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;150&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;172&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Execute 446-byte code&lt;&#x2F;text&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;185&quot; x2=&quot;145&quot; y2=&quot;205&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowOrange)&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;205&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;227&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Chain to stage 2&lt;&#x2F;text&gt;
  &lt;line x1=&quot;145&quot; y1=&quot;240&quot; x2=&quot;145&quot; y2=&quot;260&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowOrange)&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;260&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;282&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Load OS kernel&lt;&#x2F;text&gt;
  &lt;!-- UEFI flow --&gt;
&lt;p&gt;&lt;text x=&quot;435&quot; y=&quot;25&quot; fill=&quot;#00BFFF&quot; font-size=&quot;13&quot; text-anchor=&quot;middle&quot; font-weight=&quot;bold&quot;&gt;UEFI&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;340&quot; y=&quot;40&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;62&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;SEC + PEI (init)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;435&quot; y1=&quot;75&quot; x2=&quot;435&quot; y2=&quot;95&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowBlue)&quot;&#x2F;&gt;
  &lt;rect x=&quot;340&quot; y=&quot;95&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;117&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;DXE (load drivers)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;435&quot; y1=&quot;130&quot; x2=&quot;435&quot; y2=&quot;150&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowBlue)&quot;&#x2F;&gt;
  &lt;rect x=&quot;340&quot; y=&quot;150&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;172&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;BDS (find boot entry)&lt;&#x2F;text&gt;
  &lt;line x1=&quot;435&quot; y1=&quot;185&quot; x2=&quot;435&quot; y2=&quot;205&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowBlue)&quot;&#x2F;&gt;
  &lt;rect x=&quot;340&quot; y=&quot;205&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;227&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Load .EFI from ESP&lt;&#x2F;text&gt;
  &lt;line x1=&quot;435&quot; y1=&quot;240&quot; x2=&quot;435&quot; y2=&quot;260&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrowBlue)&quot;&#x2F;&gt;
  &lt;rect x=&quot;340&quot; y=&quot;260&quot; width=&quot;190&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;435&quot; y=&quot;282&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Load OS kernel&lt;&#x2F;text&gt;
  &lt;!-- Labels --&gt;
&lt;p&gt;&lt;text x=&quot;145&quot; y=&quot;320&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Blind sector load&lt;&#x2F;text&gt;
&lt;text x=&quot;145&quot; y=&quot;335&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;No filesystem awareness&lt;&#x2F;text&gt;
&lt;text x=&quot;435&quot; y=&quot;320&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;File-based boot&lt;&#x2F;text&gt;
&lt;text x=&quot;435&quot; y=&quot;335&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;Full driver model&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Arrow markers --&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arrowOrange&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;10&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arrowBlue&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;10&quot; refY=&quot;5&quot; markerWidth=&quot;6&quot; markerHeight=&quot;6&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;BIOS loads raw bytes from a disk sector. UEFI loads a named file from a filesystem on a known partition. The UEFI path is longer but far more flexible.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;UEFI defines several boot phases internally. The Security (SEC) phase runs first, initializing the CPU cache as temporary RAM. The Pre-EFI Initialization (PEI) phase trains the memory and gets DRAM working. The Driver Execution Environment (DXE) phase loads firmware drivers for storage, network, and graphics. Finally, the Boot Device Selection (BDS) phase reads the boot variables from NVRAM and loads the selected bootloader from the ESP.&lt;&#x2F;p&gt;
&lt;p&gt;The operating system never sees most of this. By the time the bootloader runs, it has access to a rich set of UEFI services -- memory allocation, file I&#x2F;O, network, console output -- that it can call through a well-defined function table. These services remain available until the OS calls &lt;code&gt;ExitBootServices()&lt;&#x2F;code&gt;, at which point the firmware gets out of the way and the OS takes full control of the hardware.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;secure-boot&quot;&gt;Secure Boot&lt;&#x2F;h2&gt;
&lt;p&gt;Secure Boot is a UEFI feature that addresses the third problem: unsigned code execution. When Secure Boot is enabled, the firmware will only load and execute EFI binaries that are signed with a trusted cryptographic key.&lt;&#x2F;p&gt;
&lt;p&gt;The trust chain works like this. The firmware ships with a database of trusted keys, called the &quot;db.&quot; It also has a database of revoked keys, called the &quot;dbx.&quot; When the firmware loads an EFI binary from the ESP, it checks the binary&#x27;s digital signature against these databases. If the signature matches a trusted key and has not been revoked, the binary runs. Otherwise, the firmware refuses to load it.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Secure Boot creates a chain of trust from firmware to bootloader to operating system. Each stage verifies the signature of the next before handing over control. This prevents bootkits -- malware that hides in the boot process below the operating system.
&lt;&#x2F;div&gt;
&lt;p&gt;In practice, most systems ship with Microsoft&#x27;s keys in the trust database because Microsoft signs the bootloaders for Windows and for the &quot;shim&quot; program that Linux distributions use. The shim is a small signed bootloader that contains the distribution&#x27;s own key. It loads GRUB, checks GRUB&#x27;s signature against that key, and GRUB in turn verifies the kernel. The chain extends from firmware to shim to GRUB to kernel.&lt;&#x2F;p&gt;
&lt;p&gt;You can add your own keys to the firmware database if you want to sign your own bootloaders. You can also disable Secure Boot entirely. The specification requires that users be able to turn it off on general-purpose PCs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;csm-the-compatibility-bridge&quot;&gt;CSM: The Compatibility Bridge&lt;&#x2F;h2&gt;
&lt;p&gt;Many UEFI systems include a feature called the Compatibility Support Module, or CSM. The CSM is essentially a legacy BIOS emulator built into the UEFI firmware. When enabled, it lets the system boot from MBR disks using the old BIOS method.&lt;&#x2F;p&gt;
&lt;p&gt;The CSM exists because the transition from BIOS to UEFI took over a decade. Operating systems, bootloaders, and recovery tools all needed time to add UEFI support. The CSM gave users and vendors a way to run old software on new hardware.&lt;&#x2F;p&gt;
&lt;p&gt;Modern systems are dropping CSM support. Intel removed it from their reference firmware starting with 11th-generation processors. If you are installing a current operating system on current hardware, you should use native UEFI boot with GPT. The only reason to use CSM today is if you need to run old operating systems that lack UEFI bootloaders.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-both-still-exist&quot;&gt;Why Both Still Exist&lt;&#x2F;h2&gt;
&lt;p&gt;BIOS is dead in new hardware. But it is alive and well in virtual machines, older servers, and embedded systems. QEMU and VirtualBox still default to BIOS-style boot in many configurations. Legacy operating systems -- anything before Windows Vista SP1 on the x86-64 side, or older Linux installers -- expect BIOS.&lt;&#x2F;p&gt;
&lt;p&gt;More importantly, the concepts from BIOS did not disappear. UEFI still performs POST. It still has to initialize memory, enumerate buses, and find a boot device. It does these things differently -- in 64-bit mode, with drivers and a filesystem -- but the sequence is recognizable. The BIOS boot process is the skeleton that UEFI built on.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
UEFI replaced BIOS as the standard firmware interface, bringing 64-bit operation, GPT disk support, Secure Boot, and a proper driver model. But the fundamental job is the same: test the hardware, find something bootable, and load it. The next step in both paths is the same -- initializing system memory so the rest of the boot process has somewhere to work.
&lt;&#x2F;div&gt;
&lt;p&gt;Understanding BIOS teaches you what firmware must accomplish. Understanding UEFI teaches you how modern systems accomplish it. You need both.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;05-memory-initialization&#x2F;&quot;&gt;Memory Initialization&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Why Linux?</title>
        <published>2025-01-05T00:00:00+00:00</published>
        <updated>2025-01-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/03b-why-linux/"/>
        <id>https://t34ch.tech/coldboot/articles/03b-why-linux/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/03b-why-linux/">&lt;p&gt;This series is about what happens between the moment you press the power button and the moment a shell prompt appears. We have covered the hardware and firmware layers so far. From here on, we need to talk about an operating system -- the software that takes control after the firmware finishes its work.&lt;&#x2F;p&gt;
&lt;p&gt;We are going to use Linux. This article explains why.&lt;&#x2F;p&gt;
&lt;p&gt;This is not a value judgment. It is not an argument that Linux is &quot;better&quot; than Windows or macOS or FreeBSD. It is a practical decision based on one overriding requirement: you should be able to see, read, and understand every piece of the system we discuss.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-requirement-inspectability&quot;&gt;The Requirement: Inspectability&lt;&#x2F;h2&gt;
&lt;p&gt;When this series describes a piece of the boot process, you should be able to open the source code and see exactly what happens. Not a summary. Not a vendor&#x27;s documentation of what they say happens. The actual code that runs on the machine.&lt;&#x2F;p&gt;
&lt;p&gt;With proprietary operating systems, this is impossible. The Windows kernel source code is not available to the public. macOS is built on an open-source foundation (XNU&#x2F;Darwin), but large portions of the system are closed. When we say &quot;the kernel does X at this stage of boot,&quot; you would have to take our word for it.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Open source&lt;&#x2F;strong&gt;
Software whose source code is publicly available for anyone to read, modify, and redistribute, subject to the terms of its license. Linux is released under the GNU General Public License version 2 (GPLv2), which requires that anyone distributing the software also make the source code available.
&lt;&#x2F;div&gt;
&lt;p&gt;With Linux, every claim in this series is verifiable. When we say the kernel initializes the memory manager at a certain point during boot, you can open &lt;code&gt;mm&#x2F;init.c&lt;&#x2F;code&gt; and read the function. When we say the init system starts services in a particular order, you can read the systemd source code or the init scripts. Nothing is hidden.&lt;&#x2F;p&gt;
&lt;p&gt;This matters because understanding a computer is not about memorizing facts. It is about building a mental model that you can verify against reality. If the model and the reality disagree, you need access to the reality to figure out which one is wrong.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-linux-runs&quot;&gt;Where Linux Runs&lt;&#x2F;h2&gt;
&lt;p&gt;Linux is not a niche operating system. It is the dominant operating system in several of the largest computing domains.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 01 -- Linux deployment across computing domains&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 320&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;320&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Servers --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;30&quot; width=&quot;160&quot; height=&quot;80&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;110&quot; y=&quot;55&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot;&gt;Servers&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;75&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;24&quot;&gt;~80%&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;of public web servers&lt;&#x2F;text&gt;
  &lt;!-- Cloud --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;30&quot; width=&quot;160&quot; height=&quot;80&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;55&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;13&quot;&gt;Cloud&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;75&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;24&quot;&gt;~90%&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;of cloud workloads&lt;&#x2F;text&gt;
  &lt;!-- Supercomputers --&gt;
  &lt;rect x=&quot;390&quot; y=&quot;30&quot; width=&quot;160&quot; height=&quot;80&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;470&quot; y=&quot;55&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;13&quot;&gt;HPC &#x2F; Top 500&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;75&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;24&quot;&gt;100%&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;of top supercomputers&lt;&#x2F;text&gt;
  &lt;!-- Embedded --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;140&quot; width=&quot;160&quot; height=&quot;80&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;110&quot; y=&quot;165&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;13&quot;&gt;Embedded&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;190&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;14&quot;&gt;Routers, TVs,&lt;&#x2F;text&gt;
  &lt;text x=&quot;110&quot; y=&quot;207&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;14&quot;&gt;cars, cameras&lt;&#x2F;text&gt;
  &lt;!-- Mobile --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;140&quot; width=&quot;160&quot; height=&quot;80&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;165&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;13&quot;&gt;Mobile&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;185&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;24&quot;&gt;~72%&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;210&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Android = Linux kernel&lt;&#x2F;text&gt;
  &lt;!-- Containers --&gt;
  &lt;rect x=&quot;390&quot; y=&quot;140&quot; width=&quot;160&quot; height=&quot;80&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;470&quot; y=&quot;165&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;13&quot;&gt;Containers&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;185&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;24&quot;&gt;~99%&lt;&#x2F;text&gt;
  &lt;text x=&quot;470&quot; y=&quot;210&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Docker&#x2F;K8s on Linux&lt;&#x2F;text&gt;
  &lt;!-- Bottom note --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;270&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot;&gt;Understanding Linux boot means understanding how most&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;286&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot;&gt;of the world&#x27;s computing infrastructure starts up.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Linux dominates servers, cloud, supercomputing, containers, and embedded devices. Android phones run the Linux kernel. Learning the Linux boot process gives you knowledge that applies across the broadest range of real systems.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;&lt;strong&gt;Servers&lt;&#x2F;strong&gt;: Roughly 80% of public-facing web servers run Linux. If you visit a website, there is a strong chance the machine serving the page is running a Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Cloud computing&lt;&#x2F;strong&gt;: AWS, Google Cloud, and Azure all offer Linux instances, and the vast majority of cloud workloads run on Linux. AWS even built their own Linux distribution (Amazon Linux) for their infrastructure.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Supercomputers&lt;&#x2F;strong&gt;: Every single system on the TOP500 list of the world&#x27;s fastest supercomputers runs Linux. One hundred percent. This has been true since 2017.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Embedded systems&lt;&#x2F;strong&gt;: Your home router almost certainly runs Linux. Many smart TVs, security cameras, automotive infotainment systems, and industrial controllers run Linux. The kernel&#x27;s configurability makes it adaptable to hardware ranging from a microcontroller with 4 MB of RAM to a server with 4 TB.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Mobile&lt;&#x2F;strong&gt;: Android, which runs on roughly 72% of the world&#x27;s smartphones, uses the Linux kernel. The userspace is different from what you would find on a server, but the kernel -- the part we will study in this series -- is the same codebase.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Containers&lt;&#x2F;strong&gt;: Docker and Kubernetes, the dominant container technologies, run on Linux. Container isolation uses Linux-specific kernel features (namespaces and cgroups) that do not exist in other kernels.&lt;&#x2F;p&gt;
&lt;p&gt;If you understand how Linux boots, you understand how most of the world&#x27;s computing infrastructure starts up.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;you-can-read-the-source&quot;&gt;You Can Read the Source&lt;&#x2F;h2&gt;
&lt;p&gt;The Linux kernel source code is available at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kernel.org&quot;&gt;kernel.org&lt;&#x2F;a&gt;. As of early 2025, it contains roughly 36 million lines of code across approximately 80,000 files. That sounds overwhelming, but the boot path -- the code that executes between the kernel being loaded and the first user process starting -- is a small, well-defined subset.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Kernel&lt;&#x2F;strong&gt;
The core of an operating system. The kernel manages hardware resources (CPU time, memory, devices), enforces security boundaries between processes, and provides the system call interface that all programs use to interact with hardware. In Linux, the kernel is a single binary (vmlinuz) loaded by the bootloader.
&lt;&#x2F;div&gt;
&lt;p&gt;Here is a concrete example. During boot, the Linux kernel prints messages to the console. You have probably seen them -- lines scrolling by during startup, each prefixed with a timestamp. The function that handles this is &lt;code&gt;printk()&lt;&#x2F;code&gt;, defined in &lt;code&gt;kernel&#x2F;printk&#x2F;printk.c&lt;&#x2F;code&gt;. You can read it. You can see how the ring buffer works, how log levels are handled, how early boot messages are stored before the console is initialized.&lt;&#x2F;p&gt;
&lt;p&gt;This level of transparency is unique. No other widely-deployed operating system gives you complete access to its internals. FreeBSD and OpenBSD do, and they are excellent systems, but they do not have Linux&#x27;s reach across servers, cloud, embedded, and mobile.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-tooling-ecosystem&quot;&gt;The Tooling Ecosystem&lt;&#x2F;h2&gt;
&lt;p&gt;Linux comes with tools that let you inspect the boot process while it is happening and after it has completed:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dmesg&lt;&#x2F;strong&gt; -- Prints the kernel&#x27;s message buffer, showing every hardware detection, driver initialization, and boot event in chronological order.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;journalctl&lt;&#x2F;strong&gt; -- On systemd-based systems, shows the complete log of the boot process, including both kernel and userspace messages.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&#x2F;proc and &#x2F;sys&lt;&#x2F;strong&gt; -- Virtual filesystems that expose kernel state at runtime. Want to know what the kernel detected about your CPU? Read &lt;code&gt;&#x2F;proc&#x2F;cpuinfo&lt;&#x2F;code&gt;. Want to see the memory map? Read &lt;code&gt;&#x2F;proc&#x2F;iomem&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;strace&lt;&#x2F;strong&gt; -- Traces system calls made by any process, letting you see exactly how programs interact with the kernel.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ftrace &#x2F; perf&lt;&#x2F;strong&gt; -- Kernel tracing tools that can instrument the boot process itself, showing you the exact sequence of function calls and their timing.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 02 -- Inspecting the boot process with Linux tools&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Boot timeline --&gt;
  &lt;line x1=&quot;40&quot; y1=&quot;40&quot; x2=&quot;540&quot; y2=&quot;40&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;40&quot; y=&quot;30&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Kernel loaded&lt;&#x2F;text&gt;
  &lt;text x=&quot;480&quot; y=&quot;30&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Shell prompt&lt;&#x2F;text&gt;
  &lt;!-- Phase blocks on timeline --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;45&quot; width=&quot;120&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;62&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;Early kernel init&lt;&#x2F;text&gt;
  &lt;rect x=&quot;165&quot; y=&quot;45&quot; width=&quot;120&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;225&quot; y=&quot;62&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;Driver probing&lt;&#x2F;text&gt;
  &lt;rect x=&quot;290&quot; y=&quot;45&quot; width=&quot;100&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;340&quot; y=&quot;62&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;Root mount&lt;&#x2F;text&gt;
  &lt;rect x=&quot;395&quot; y=&quot;45&quot; width=&quot;140&quot; height=&quot;25&quot; rx=&quot;3&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;465&quot; y=&quot;62&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Userspace init&lt;&#x2F;text&gt;
  &lt;!-- Tools pointing to phases --&gt;
  &lt;!-- dmesg --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;100&quot; width=&quot;130&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;50&quot; y=&quot;122&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot;&gt;$ dmesg&lt;&#x2F;text&gt;
  &lt;line x1=&quot;95&quot; y1=&quot;100&quot; x2=&quot;95&quot; y2=&quot;75&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;text x=&quot;30&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Kernel ring buffer --&lt;&#x2F;text&gt;
  &lt;text x=&quot;30&quot; y=&quot;163&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;hardware + driver messages&lt;&#x2F;text&gt;
  &lt;!-- journalctl --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;100&quot; width=&quot;170&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;240&quot; y=&quot;122&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot;&gt;$ journalctl -b&lt;&#x2F;text&gt;
  &lt;line x1=&quot;305&quot; y1=&quot;100&quot; x2=&quot;305&quot; y2=&quot;75&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;text x=&quot;220&quot; y=&quot;150&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Full boot log: kernel +&lt;&#x2F;text&gt;
  &lt;text x=&quot;220&quot; y=&quot;163&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;systemd + services&lt;&#x2F;text&gt;
  &lt;!-- &#x2F;proc --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;195&quot; width=&quot;150&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;50&quot; y=&quot;217&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot;&gt;$ cat &#x2F;proc&#x2F;iomem&lt;&#x2F;text&gt;
  &lt;text x=&quot;30&quot; y=&quot;245&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Physical memory map --&lt;&#x2F;text&gt;
  &lt;text x=&quot;30&quot; y=&quot;258&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;what the kernel detected&lt;&#x2F;text&gt;
  &lt;!-- systemd-analyze --&gt;
  &lt;rect x=&quot;220&quot; y=&quot;195&quot; width=&quot;210&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;240&quot; y=&quot;217&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot;&gt;$ systemd-analyze blame&lt;&#x2F;text&gt;
  &lt;text x=&quot;220&quot; y=&quot;245&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Time spent in each service&lt;&#x2F;text&gt;
  &lt;text x=&quot;220&quot; y=&quot;258&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;during boot&lt;&#x2F;text&gt;
  &lt;!-- ftrace --&gt;
  &lt;rect x=&quot;460&quot; y=&quot;195&quot; width=&quot;100&quot; height=&quot;35&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;480&quot; y=&quot;217&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot;&gt;ftrace&lt;&#x2F;text&gt;
  &lt;text x=&quot;460&quot; y=&quot;245&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Function-level&lt;&#x2F;text&gt;
  &lt;text x=&quot;460&quot; y=&quot;258&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;kernel tracing&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Linux provides tools to inspect every phase of the boot process, from kernel ring buffer messages to systemd timing analysis to runtime kernel tracing.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;These tools are not afterthoughts. They are built into the system specifically because Linux is designed to be understood. The kernel developers themselves use these tools to debug boot issues, and they are available to anyone running a Linux system.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Linux provides complete source code and built-in inspection tools (dmesg, journalctl, &#x2F;proc, &#x2F;sys, ftrace) that let you verify every claim about how the system works. No other widely-deployed OS offers this combination of transparency, tooling, and market reach.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-linux-means-in-this-series&quot;&gt;What &quot;Linux&quot; Means in This Series&lt;&#x2F;h2&gt;
&lt;p&gt;When people say &quot;Linux,&quot; they sometimes mean just the kernel, and sometimes mean an entire operating system including the kernel, system libraries, package manager, desktop environment, and applications. In this series, we will be precise about which we mean.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The Linux kernel&lt;&#x2F;strong&gt; is the software written by Linus Torvalds and thousands of contributors, maintained at kernel.org. It handles hardware management, process scheduling, memory management, filesystems, networking, and security. When we say &quot;the kernel does X,&quot; we mean this specific piece of software.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;A Linux distribution&lt;&#x2F;strong&gt; (distro) is a complete operating system built around the Linux kernel. It includes a bootloader (often GRUB), an init system (often systemd), system libraries (glibc or musl), a package manager (apt, dnf, pacman), and a collection of user applications. Examples include Debian, Fedora, Arch Linux, Ubuntu, and Alpine.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 03 -- Components of a Linux distribution&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 340&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;340&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Hardware layer --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;280&quot; width=&quot;500&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;305&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;13&quot;&gt;Hardware (CPU, RAM, Disk, Network)&lt;&#x2F;text&gt;
  &lt;!-- Kernel layer --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;220&quot; width=&quot;500&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;245&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;14&quot;&gt;Linux Kernel&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;262&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Process mgmt | Memory mgmt | Filesystems | Drivers | Networking&lt;&#x2F;text&gt;
  &lt;!-- System libraries --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;160&quot; width=&quot;240&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;160&quot; y=&quot;185&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot;&gt;System Libraries&lt;&#x2F;text&gt;
  &lt;text x=&quot;160&quot; y=&quot;200&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;glibc &#x2F; musl&lt;&#x2F;text&gt;
  &lt;!-- Init system --&gt;
  &lt;rect x=&quot;300&quot; y=&quot;160&quot; width=&quot;240&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;420&quot; y=&quot;185&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot;&gt;Init System&lt;&#x2F;text&gt;
  &lt;text x=&quot;420&quot; y=&quot;200&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;systemd &#x2F; OpenRC &#x2F; runit&lt;&#x2F;text&gt;
  &lt;!-- Shell and utilities --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;100&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;120&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot;&gt;Shell + Utils&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;140&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;bash, coreutils&lt;&#x2F;text&gt;
  &lt;!-- Package manager --&gt;
  &lt;rect x=&quot;210&quot; y=&quot;100&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot;&gt;Package Mgr&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;140&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;apt &#x2F; dnf &#x2F; pacman&lt;&#x2F;text&gt;
  &lt;!-- Applications --&gt;
  &lt;rect x=&quot;380&quot; y=&quot;100&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;460&quot; y=&quot;125&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot;&gt;Applications&lt;&#x2F;text&gt;
  &lt;text x=&quot;460&quot; y=&quot;140&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;nginx, postgres, ...&lt;&#x2F;text&gt;
  &lt;!-- Bootloader --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;40&quot; width=&quot;500&quot; height=&quot;45&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;60&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot;&gt;Bootloader (GRUB &#x2F; systemd-boot)&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;77&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Loads kernel from disk into memory&lt;&#x2F;text&gt;
  &lt;!-- Right bracket: &quot;This series&quot; spans bootloader through hardware --&gt;
  &lt;line x1=&quot;555&quot; y1=&quot;45&quot; x2=&quot;565&quot; y2=&quot;45&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;565&quot; y1=&quot;45&quot; x2=&quot;565&quot; y2=&quot;315&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;555&quot; y1=&quot;315&quot; x2=&quot;565&quot; y2=&quot;315&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Left label (rotated) --&gt;
&lt;p&gt;&lt;text x=&quot;16&quot; y=&quot;180&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; transform=&quot;rotate(-90,16,180)&quot;&gt;This series&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A Linux distribution is a complete system built in layers. This series covers the full stack from bootloader through kernel initialization to the first shell prompt.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;This series covers the boot process from firmware handoff (where the bootloader takes over) through kernel initialization to the moment the first user process runs. That path touches the bootloader, the kernel, the init system, and the early userspace -- components found in every Linux distribution.&lt;&#x2F;p&gt;
&lt;p&gt;Where distribution-specific details matter (such as how GRUB is configured or how systemd orders its services), we will note which distribution we are using and point out where other distributions differ.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-not-windows-why-not-bsd&quot;&gt;Why Not Windows? Why Not BSD?&lt;&#x2F;h2&gt;
&lt;p&gt;Windows is a fine operating system. It boots, it runs applications, it handles hardware. But its boot process is closed. You cannot read the Windows kernel source code. You cannot see what &lt;code&gt;ntoskrnl.exe&lt;&#x2F;code&gt; does during initialization. You cannot trace the exact sequence of operations from bootloader to desktop. You can study Microsoft&#x27;s documentation, which is extensive, but documentation is not source code.&lt;&#x2F;p&gt;
&lt;p&gt;FreeBSD and OpenBSD are open-source, well-documented, and technically excellent. Their boot processes are worth studying. But they serve a smaller user base. If you learn the FreeBSD boot process, you understand how a few percent of servers start up. If you learn the Linux boot process, you understand how the majority of the world&#x27;s servers, all of its supercomputers, most of its cloud infrastructure, and billions of mobile devices start up.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Distribution (distro)&lt;&#x2F;strong&gt;
A complete operating system package that includes the Linux kernel, bootloader, init system, system libraries, package manager, and applications. Different distributions make different choices about these components, but they all share the same kernel. Debian, Fedora, Arch, and Ubuntu are all Linux distributions.
&lt;&#x2F;div&gt;
&lt;p&gt;This is not about allegiance. It is about reach. The knowledge you gain from studying the Linux boot process transfers to more real-world systems than any alternative.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-you-will-need&quot;&gt;What You Will Need&lt;&#x2F;h2&gt;
&lt;p&gt;To follow along with this series, you will want access to a Linux system. This could be:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A physical machine&lt;&#x2F;strong&gt; running any Linux distribution. Debian, Fedora, Ubuntu, Arch -- any will work.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A virtual machine&lt;&#x2F;strong&gt; using VirtualBox, QEMU&#x2F;KVM, or VMware. This is the safest option for experimentation, since you can snapshot and restore.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A cloud instance&lt;&#x2F;strong&gt; on any provider. A small Debian or Ubuntu instance is inexpensive and gives you full root access.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Windows Subsystem for Linux (WSL2)&lt;&#x2F;strong&gt; -- usable for many exercises, though it does not boot a real Linux kernel in the traditional sense (the kernel is provided by Microsoft&#x27;s lightweight VM).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The specific distribution does not matter much for this series. We will point out distribution-specific details when they arise. What matters is that you have root access and can inspect the system freely.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
This series uses Linux because it is open-source (you can read every line of code), dominant (it runs most of the world&#x27;s servers, cloud, and mobile devices), and well-tooled (dmesg, &#x2F;proc, ftrace give you direct visibility into the boot process). It is a practical choice, not a tribal one.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-comes-next&quot;&gt;What Comes Next&lt;&#x2F;h2&gt;
&lt;p&gt;We have covered the hardware layer (power delivery, the reset vector) and the firmware layer (POST and the BIOS). We briefly discussed why the legacy BIOS has limitations. The next article tackles the firmware that replaced it: UEFI.&lt;&#x2F;p&gt;
&lt;p&gt;UEFI changes the boot process significantly. It replaces the 512-byte MBR with a proper filesystem on a dedicated partition. It runs in 32-bit or 64-bit mode instead of real mode. It provides Secure Boot to verify the integrity of everything in the boot chain. And it standardizes the interface between firmware and operating system in ways the legacy BIOS never did.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;04-uefi-vs-legacy-bios&#x2F;&quot;&gt;UEFI vs Legacy BIOS&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>POST and the BIOS</title>
        <published>2025-01-04T00:00:00+00:00</published>
        <updated>2025-01-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/03-post-and-the-bios/"/>
        <id>https://t34ch.tech/coldboot/articles/03-post-and-the-bios/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/03-post-and-the-bios/">&lt;p&gt;The CPU has fetched its first instruction from the reset vector and jumped to the main body of the BIOS firmware. No operating system is running. No drivers are loaded. The firmware is alone with the bare hardware, and it has one job: get the system into a state where an operating system can take over.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing the firmware does is test whether the hardware is working at all. This test has a name that has survived four decades of computing: the Power-On Self Test, or POST.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-the-bios&quot;&gt;What Is the BIOS?&lt;&#x2F;h2&gt;
&lt;p&gt;BIOS stands for Basic Input&#x2F;Output System. It is firmware -- software permanently stored on a chip on the motherboard. Unlike programs you install on a hard drive, the BIOS is present from the factory. It is the first code that runs on the machine.&lt;&#x2F;p&gt;
&lt;p&gt;The original IBM PC BIOS, released in 1981, fit in 8 KB of ROM. It provided basic routines for reading the keyboard, writing characters to the screen, and accessing floppy disks. Modern BIOS firmware (or its successor, UEFI) is measured in megabytes and handles tasks that the original designers never imagined: USB, PCIe, SATA, network boot, Secure Boot, and more.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: BIOS (Basic Input&#x2F;Output System)&lt;&#x2F;strong&gt;
Firmware stored on a chip on the motherboard that initializes hardware and provides basic services during the boot process. The BIOS runs before the operating system and is responsible for bringing the hardware from a raw, uninitialized state to a state where an OS can be loaded.
&lt;&#x2F;div&gt;
&lt;p&gt;Regardless of how complex modern firmware has become, the first task remains the same: test the hardware.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-power-on-self-test&quot;&gt;The Power-On Self Test&lt;&#x2F;h2&gt;
&lt;p&gt;POST is a series of diagnostic checks that the firmware performs immediately after gaining control of the CPU. These tests verify that the most fundamental hardware components are working before the firmware attempts anything more complex.&lt;&#x2F;p&gt;
&lt;p&gt;POST is not a single test. It is an ordered sequence of tests, and the order matters. The firmware tests the most basic components first, because later tests depend on earlier components working. You cannot test RAM if the memory controller is broken. You cannot display an error message if the video card is dead.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 01 -- POST test sequence&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 420&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;420&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Step 1 --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;15&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;40&quot; fill=&quot;#FFD700&quot; font-size=&quot;24&quot;&gt;1&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;40&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;CPU register test&lt;&#x2F;text&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;55&quot; x2=&quot;150&quot; y2=&quot;75&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr03a)&quot;&#x2F;&gt;
  &lt;!-- Step 2 --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;75&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;100&quot; fill=&quot;#FFD700&quot; font-size=&quot;24&quot;&gt;2&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;100&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;ROM checksum&lt;&#x2F;text&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;115&quot; x2=&quot;150&quot; y2=&quot;135&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr03a)&quot;&#x2F;&gt;
  &lt;!-- Step 3 --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;135&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;160&quot; fill=&quot;#FF6600&quot; font-size=&quot;24&quot;&gt;3&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;160&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;Timer initialization&lt;&#x2F;text&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;175&quot; x2=&quot;150&quot; y2=&quot;195&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr03a)&quot;&#x2F;&gt;
  &lt;!-- Step 4 --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;195&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;220&quot; fill=&quot;#FF6600&quot; font-size=&quot;24&quot;&gt;4&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;220&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;DMA controller test&lt;&#x2F;text&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;235&quot; x2=&quot;150&quot; y2=&quot;255&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr03a)&quot;&#x2F;&gt;
  &lt;!-- Step 5 --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;255&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;280&quot; fill=&quot;#00BFFF&quot; font-size=&quot;24&quot;&gt;5&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;280&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;Memory controller init&lt;&#x2F;text&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;295&quot; x2=&quot;150&quot; y2=&quot;315&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr03a)&quot;&#x2F;&gt;
  &lt;!-- Step 6 --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;315&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;340&quot; fill=&quot;#00BFFF&quot; font-size=&quot;24&quot;&gt;6&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;340&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;RAM test&lt;&#x2F;text&gt;
  &lt;line x1=&quot;150&quot; y1=&quot;355&quot; x2=&quot;150&quot; y2=&quot;375&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot; marker-end=&quot;url(#arr03a)&quot;&#x2F;&gt;
  &lt;!-- Step 7 --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;375&quot; width=&quot;200&quot; height=&quot;40&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;400&quot; fill=&quot;#39D353&quot; font-size=&quot;24&quot;&gt;7&lt;&#x2F;text&gt;
  &lt;text x=&quot;120&quot; y=&quot;400&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;Video initialization&lt;&#x2F;text&gt;
  &lt;!-- Right side annotations --&gt;
&lt;p&gt;&lt;text x=&quot;280&quot; y=&quot;40&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;No RAM, no display&lt;&#x2F;text&gt;
&lt;text x=&quot;280&quot; y=&quot;100&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;Verify BIOS not corrupt&lt;&#x2F;text&gt;
&lt;text x=&quot;280&quot; y=&quot;160&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;System timer (PIT&#x2F;HPET)&lt;&#x2F;text&gt;
&lt;text x=&quot;280&quot; y=&quot;220&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;Direct Memory Access&lt;&#x2F;text&gt;
&lt;text x=&quot;280&quot; y=&quot;280&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;Read SPD, train DIMMs&lt;&#x2F;text&gt;
&lt;text x=&quot;280&quot; y=&quot;340&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;Write&#x2F;read patterns&lt;&#x2F;text&gt;
&lt;text x=&quot;280&quot; y=&quot;400&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;First visual output&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Phase brackets on far right --&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;20&quot; x2=&quot;480&quot; y2=&quot;20&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;20&quot; x2=&quot;480&quot; y2=&quot;110&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;110&quot; x2=&quot;480&quot; y2=&quot;110&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;495&quot; y=&quot;70&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;Silent&lt;&#x2F;text&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;140&quot; x2=&quot;480&quot; y2=&quot;140&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;140&quot; x2=&quot;480&quot; y2=&quot;230&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;230&quot; x2=&quot;480&quot; y2=&quot;230&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;495&quot; y=&quot;185&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;Beep&lt;&#x2F;text&gt;
  &lt;text x=&quot;495&quot; y=&quot;198&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;codes&lt;&#x2F;text&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;260&quot; x2=&quot;480&quot; y2=&quot;260&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;260&quot; x2=&quot;480&quot; y2=&quot;350&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;350&quot; x2=&quot;480&quot; y2=&quot;350&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;495&quot; y=&quot;305&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;RAM&lt;&#x2F;text&gt;
  &lt;text x=&quot;495&quot; y=&quot;318&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;available&lt;&#x2F;text&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;380&quot; x2=&quot;480&quot; y2=&quot;380&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;480&quot; y1=&quot;380&quot; x2=&quot;480&quot; y2=&quot;410&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;470&quot; y1=&quot;410&quot; x2=&quot;480&quot; y2=&quot;410&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;495&quot; y=&quot;400&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;Display&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr03a&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;4&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#8C9097&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;POST tests are ordered by dependency. The earliest tests run with no RAM and no display. Only after memory is initialized and tested can the firmware use a stack or show anything on screen.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h3 id=&quot;cpu-register-test&quot;&gt;CPU Register Test&lt;&#x2F;h3&gt;
&lt;p&gt;The very first test checks whether the CPU&#x27;s own registers work correctly. The firmware writes known values to each register and reads them back. If a register cannot hold a value, the CPU is fundamentally broken and nothing else can proceed.&lt;&#x2F;p&gt;
&lt;p&gt;This test runs without RAM (which has not been initialized yet) and without any display output. If it fails, the system halts silently or the motherboard signals the failure through a POST code display or a pattern of beeps from the speaker.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rom-checksum-verification&quot;&gt;ROM Checksum Verification&lt;&#x2F;h3&gt;
&lt;p&gt;Next, the firmware verifies its own integrity. It reads through the entire BIOS ROM and computes a checksum -- a mathematical summary of all the bytes. If the checksum does not match the expected value, the firmware itself is corrupt. This can happen due to a failed firmware update, a degraded flash chip, or cosmic ray bit-flips (rare but real).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;memory-controller-initialization&quot;&gt;Memory Controller Initialization&lt;&#x2F;h3&gt;
&lt;p&gt;This is one of the most complex and important tasks POST performs. The firmware must:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Detect which DIMM slots have memory installed.&lt;&#x2F;li&gt;
&lt;li&gt;Read the SPD data from each DIMM to learn its specifications.&lt;&#x2F;li&gt;
&lt;li&gt;Configure the memory controller with the correct speed, timings, and voltage.&lt;&#x2F;li&gt;
&lt;li&gt;&quot;Train&quot; the memory interface -- adjusting signal timing to account for the physical characteristics of the traces on the motherboard.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: SPD (Serial Presence Detect)&lt;&#x2F;strong&gt;
A small EEPROM chip on each memory DIMM that contains information about the module&#x27;s capacity, speed, timings, and voltage requirements. The BIOS reads SPD data during POST to configure the memory controller correctly.
&lt;&#x2F;div&gt;
&lt;p&gt;Memory training is a process where the firmware sends test patterns through the memory interface and adjusts timing parameters until data can be read back reliably. This process can take several hundred milliseconds -- it is one reason why turning on a computer is not instantaneous.&lt;&#x2F;p&gt;
&lt;p&gt;Once memory is initialized and tested, the firmware finally has RAM to work with. It can set up a stack, allocate buffers, and store variables. The execution environment goes from &quot;CPU registers only&quot; to something resembling a normal programming environment.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ram-test&quot;&gt;RAM Test&lt;&#x2F;h3&gt;
&lt;p&gt;After the memory controller is configured, the firmware tests the RAM itself. The classic RAM test writes a pattern to every address (often alternating 0x55 and 0xAA, which represent alternating bit patterns) and reads it back. If any location fails to hold its value, the firmware knows that RAM module is defective.&lt;&#x2F;p&gt;
&lt;p&gt;Modern systems often perform a quick RAM test rather than testing every byte, because testing 64 GB of memory byte-by-byte would take a very long time. The BIOS setup menu usually has an option to enable a thorough memory test if you suspect a problem.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;video-initialization&quot;&gt;Video Initialization&lt;&#x2F;h3&gt;
&lt;p&gt;Once RAM is working, the firmware initializes the video system. On a machine with a discrete graphics card, this involves loading and executing the video card&#x27;s option ROM -- firmware stored on the graphics card itself. On systems with integrated graphics, the main BIOS handles video initialization directly.&lt;&#x2F;p&gt;
&lt;p&gt;This is the moment when you first see something on the screen. Before this point, the monitor has been receiving no signal. Now, the BIOS can display its manufacturer logo or a text-mode screen showing POST progress.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
POST follows a strict order: CPU test, ROM checksum, timer and DMA setup, memory initialization, RAM test, then video. Each step depends on the previous one succeeding. The earliest tests run with no RAM and no display -- if they fail, the only feedback is through beep codes or diagnostic LEDs.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;beep-codes-when-the-screen-is-not-available&quot;&gt;Beep Codes: When the Screen Is Not Available&lt;&#x2F;h2&gt;
&lt;p&gt;What happens when POST detects a failure before the video system is initialized? The firmware cannot display an error message because the display is not working yet. Instead, it uses the only output device available at that stage: the PC speaker.&lt;&#x2F;p&gt;
&lt;p&gt;The BIOS generates a pattern of beeps to indicate which test failed. These patterns are called beep codes, and they vary by BIOS manufacturer.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 02 -- Common beep codes (Award BIOS)&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 250&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;250&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Table header --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;15&quot; width=&quot;540&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;120&quot; y=&quot;35&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot;&gt;Beep Pattern&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;35&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot;&gt;Meaning&lt;&#x2F;text&gt;
  &lt;!-- Row 1 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;50&quot; width=&quot;540&quot; height=&quot;35&quot; rx=&quot;0&quot; fill=&quot;#35383C&quot; stroke=&quot;#494D52&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- 1 short beep visualization --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;60&quot; width=&quot;30&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;120&quot; y=&quot;72&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;1 short&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;72&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;POST successful -- all OK&lt;&#x2F;text&gt;
  &lt;!-- Row 2 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;85&quot; width=&quot;540&quot; height=&quot;35&quot; rx=&quot;0&quot; fill=&quot;#35383C&quot; stroke=&quot;#494D52&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;95&quot; width=&quot;60&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;120&quot; y=&quot;107&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;1 long&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;107&quot; text-anchor=&quot;middle&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot;&gt;DRAM refresh failure&lt;&#x2F;text&gt;
  &lt;!-- Row 3 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;120&quot; width=&quot;540&quot; height=&quot;35&quot; rx=&quot;0&quot; fill=&quot;#35383C&quot; stroke=&quot;#494D52&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;130&quot; width=&quot;60&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;rect x=&quot;120&quot; y=&quot;130&quot; width=&quot;30&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;rect x=&quot;160&quot; y=&quot;130&quot; width=&quot;30&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;220&quot; y=&quot;142&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;1 long + 2 short&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;142&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot;&gt;Video card failure&lt;&#x2F;text&gt;
  &lt;!-- Row 4 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;155&quot; width=&quot;540&quot; height=&quot;35&quot; rx=&quot;0&quot; fill=&quot;#35383C&quot; stroke=&quot;#494D52&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;165&quot; width=&quot;60&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;rect x=&quot;120&quot; y=&quot;165&quot; width=&quot;30&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;rect x=&quot;160&quot; y=&quot;165&quot; width=&quot;30&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;rect x=&quot;200&quot; y=&quot;165&quot; width=&quot;30&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;250&quot; y=&quot;177&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;1 long + 3 short&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;177&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot;&gt;Keyboard controller error&lt;&#x2F;text&gt;
  &lt;!-- Row 5 --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;190&quot; width=&quot;540&quot; height=&quot;35&quot; rx=&quot;0&quot; fill=&quot;#35383C&quot; stroke=&quot;#494D52&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;rect x=&quot;50&quot; y=&quot;200&quot; width=&quot;60&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;rect x=&quot;118&quot; y=&quot;200&quot; width=&quot;60&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;rect x=&quot;186&quot; y=&quot;200&quot; width=&quot;60&quot; height=&quot;15&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;270&quot; y=&quot;212&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;continuous long&lt;&#x2F;text&gt;
  &lt;text x=&quot;370&quot; y=&quot;212&quot; text-anchor=&quot;middle&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot;&gt;Memory not detected&lt;&#x2F;text&gt;
  &lt;!-- Legend --&gt;
  &lt;rect x=&quot;50&quot; y=&quot;232&quot; width=&quot;30&quot; height=&quot;10&quot; rx=&quot;2&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
  &lt;text x=&quot;90&quot; y=&quot;242&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;short&lt;&#x2F;text&gt;
  &lt;rect x=&quot;150&quot; y=&quot;232&quot; width=&quot;60&quot; height=&quot;10&quot; rx=&quot;2&quot; fill=&quot;#C0392B&quot;&#x2F;&gt;
  &lt;text x=&quot;220&quot; y=&quot;242&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;long&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Beep codes encode error information in patterns of long and short tones. One short beep means success. Longer or repeated patterns indicate specific hardware failures detected during POST.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;A single short beep from an Award BIOS means POST completed successfully. One long beep followed by two short beeps means the video card failed. Continuous long beeps mean no memory was detected. Each BIOS vendor (Award, AMI, Phoenix) has its own set of codes.&lt;&#x2F;p&gt;
&lt;p&gt;Modern motherboards often replace or supplement beep codes with a two-digit hexadecimal POST code display -- a pair of seven-segment LEDs on the board that show the current POST stage. If the system hangs, the displayed code tells you exactly which test it got stuck on. These codes are listed in the motherboard manual.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;beyond-post-hardware-enumeration&quot;&gt;Beyond POST: Hardware Enumeration&lt;&#x2F;h2&gt;
&lt;p&gt;Once POST confirms that the basic hardware is functional, the BIOS moves on to more complex initialization. This phase detects and configures all the devices attached to the system.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pci-pcie-bus-enumeration&quot;&gt;PCI&#x2F;PCIe Bus Enumeration&lt;&#x2F;h3&gt;
&lt;p&gt;The BIOS scans the PCI and PCIe buses to discover what devices are installed -- graphics cards, network adapters, storage controllers, sound cards. Each device has a set of configuration registers that the BIOS reads to identify the device and assign it resources (memory-mapped I&#x2F;O regions, interrupt lines, and so on).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;option-rom-execution&quot;&gt;Option ROM Execution&lt;&#x2F;h3&gt;
&lt;p&gt;Many expansion cards carry their own firmware, called an option ROM. The video card&#x27;s option ROM initializes the GPU and provides basic display services. A network card&#x27;s option ROM might provide PXE boot capability. A RAID controller&#x27;s option ROM provides access to its disk arrays.&lt;&#x2F;p&gt;
&lt;p&gt;The BIOS scans for option ROMs in a specific memory range (0xC0000 to 0xDFFFF), validates their checksums, and executes them one by one. This is why you sometimes see a separate splash screen from your graphics card or RAID controller before the main BIOS screen appears.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Option ROM&lt;&#x2F;strong&gt;
Firmware stored on an expansion card (such as a graphics card or network adapter) that extends the BIOS with device-specific initialization code and services. The BIOS discovers and executes option ROMs during POST.
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;interrupt-vector-table&quot;&gt;Interrupt Vector Table&lt;&#x2F;h3&gt;
&lt;p&gt;The BIOS sets up the interrupt vector table (IVT) in the first 1 KB of RAM (addresses 0x0000 to 0x03FF). This table contains 256 entries, each pointing to a routine that handles a specific interrupt. Hardware interrupts from the keyboard, timer, and disk controller all route through this table.&lt;&#x2F;p&gt;
&lt;p&gt;The IVT is a real-mode structure, and it will be replaced entirely when the operating system switches to protected mode. But during the boot process, everything -- keyboard input, disk reads, screen output -- relies on the BIOS interrupt handlers in this table.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-bios-setup-screen&quot;&gt;The BIOS Setup Screen&lt;&#x2F;h2&gt;
&lt;p&gt;You have probably seen it: press Delete or F2 during POST and you get a screen full of settings. This is the BIOS setup utility. It allows you to configure boot order, memory timings, CPU settings, and dozens of other parameters.&lt;&#x2F;p&gt;
&lt;p&gt;These settings are stored in a small battery-backed memory called CMOS RAM (or, on modern systems, in a section of the SPI flash chip). The battery -- the coin cell on your motherboard -- keeps these settings alive when the system is powered off.&lt;&#x2F;p&gt;
&lt;p&gt;The BIOS reads these settings during POST to determine how to configure the hardware. If the CMOS battery dies, the settings revert to factory defaults, which is why a dead CMOS battery often causes the system to lose its date and time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;finding-a-boot-device&quot;&gt;Finding a Boot Device&lt;&#x2F;h2&gt;
&lt;p&gt;After all hardware is initialized and tested, the BIOS has one final task: find an operating system to load.&lt;&#x2F;p&gt;
&lt;p&gt;The BIOS checks devices in the order specified by the boot priority list (configured in the BIOS setup). For each device, it attempts to read the first sector -- 512 bytes -- from the device. If the last two bytes of that sector are 0x55 and 0xAA (the boot signature), the BIOS considers the device bootable.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 03 -- Boot device search sequence&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 300&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;300&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- BIOS box --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;20&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;80&quot; y=&quot;50&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot;&gt;BIOS&lt;&#x2F;text&gt;
  &lt;!-- Arrow to first device --&gt;
  &lt;line x1=&quot;130&quot; y1=&quot;45&quot; x2=&quot;180&quot; y2=&quot;45&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr03b)&quot;&#x2F;&gt;
  &lt;!-- Device 1: USB --&gt;
  &lt;rect x=&quot;180&quot; y=&quot;20&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;42&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;USB Drive&lt;&#x2F;text&gt;
  &lt;text x=&quot;235&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; fill=&quot;#C0392B&quot; font-size=&quot;10&quot;&gt;No boot sig&lt;&#x2F;text&gt;
  &lt;!-- Arrow to second device --&gt;
  &lt;path d=&quot;M235,70 L235,95 L355,95&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr03c)&quot;&#x2F;&gt;
  &lt;text x=&quot;295&quot; y=&quot;88&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;try next&lt;&#x2F;text&gt;
  &lt;!-- Device 2: SSD --&gt;
  &lt;rect x=&quot;355&quot; y=&quot;75&quot; width=&quot;110&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;410&quot; y=&quot;95&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;SSD (sda)&lt;&#x2F;text&gt;
  &lt;text x=&quot;410&quot; y=&quot;112&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;0x55AA found!&lt;&#x2F;text&gt;
  &lt;!-- Arrow down from SSD to MBR detail --&gt;
  &lt;line x1=&quot;410&quot; y1=&quot;125&quot; x2=&quot;410&quot; y2=&quot;155&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr03d)&quot;&#x2F;&gt;
  &lt;!-- MBR detail --&gt;
  &lt;rect x=&quot;170&quot; y=&quot;155&quot; width=&quot;380&quot; height=&quot;60&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- MBR segments --&gt;
  &lt;rect x=&quot;185&quot; y=&quot;170&quot; width=&quot;100&quot; height=&quot;30&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;190&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;Boot code&lt;&#x2F;text&gt;
  &lt;rect x=&quot;295&quot; y=&quot;170&quot; width=&quot;120&quot; height=&quot;30&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;355&quot; y=&quot;190&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;Partition table&lt;&#x2F;text&gt;
  &lt;rect x=&quot;425&quot; y=&quot;170&quot; width=&quot;60&quot; height=&quot;30&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;455&quot; y=&quot;190&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;0x55AA&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;360&quot; y=&quot;230&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Sector 0 (512 bytes) = Master Boot Record&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Load into memory --&gt;
  &lt;line x1=&quot;360&quot; y1=&quot;240&quot; x2=&quot;360&quot; y2=&quot;270&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr03e)&quot;&#x2F;&gt;
  &lt;rect x=&quot;260&quot; y=&quot;270&quot; width=&quot;200&quot; height=&quot;25&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;360&quot; y=&quot;288&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot;&gt;Load to 0x7C00, JMP&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr03b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr03c&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr03d&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;4&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr03e&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;4&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The BIOS checks each boot device in priority order. When it finds a device whose first sector ends with the 0x55AA signature, it loads that sector into memory at address 0x7C00 and jumps to it.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The BIOS loads those 512 bytes into RAM at address &lt;strong&gt;0x7C00&lt;&#x2F;strong&gt; and jumps to that address. Control passes from the firmware to whatever code was in that boot sector. On a legacy BIOS system, this is the Master Boot Record (MBR), which typically contains a small bootloader that knows how to find and load a larger bootloader (like GRUB), which in turn loads the operating system kernel.&lt;&#x2F;p&gt;
&lt;p&gt;The address 0x7C00 is another one of those historical artifacts. It was chosen by the designers of the original IBM PC 5150 in 1981. The number has no deep significance -- it was simply a convenient location in memory that would not conflict with anything else. But because the entire PC ecosystem depends on it, it has persisted for over four decades.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The BIOS completes POST, initializes all hardware, enumerates buses, executes option ROMs, and then searches for a bootable device. When found, it loads the boot sector (512 bytes) to address 0x7C00 and transfers control to it. This is the moment firmware hands off to the boot process chain.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;the-bios-data-area&quot;&gt;The BIOS Data Area&lt;&#x2F;h2&gt;
&lt;p&gt;During POST, the BIOS writes a collection of data to a reserved region of RAM starting at address 0x0400, known as the BIOS Data Area (BDA). This region contains information the BIOS has gathered about the system: the number and type of disk drives, the amount of conventional memory, the keyboard buffer, serial and parallel port addresses, and the current video mode.&lt;&#x2F;p&gt;
&lt;p&gt;The BDA is a communication channel. The BIOS writes it; early boot code and real-mode operating systems read it. It is yet another structure that only matters in real mode and will be overwritten once the operating system takes over.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;limitations-of-the-legacy-bios&quot;&gt;Limitations of the Legacy BIOS&lt;&#x2F;h2&gt;
&lt;p&gt;The traditional BIOS, for all its importance, has significant limitations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Real mode only&lt;&#x2F;strong&gt;: The BIOS runs in 16-bit real mode with a 1 MB address limit. It cannot directly use modern CPU features.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;MBR partition limit&lt;&#x2F;strong&gt;: The MBR partition table supports a maximum of four primary partitions and disks up to 2 TB.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;No standard security model&lt;&#x2F;strong&gt;: There is no mechanism to verify that the code being loaded is authentic.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;No standard driver model&lt;&#x2F;strong&gt;: Each device needs its own option ROM; there is no plug-in driver architecture.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Slow initialization&lt;&#x2F;strong&gt;: The sequential, one-device-at-a-time nature of POST is slow on modern systems with many devices.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These limitations led to the development of UEFI, which replaces the legacy BIOS with a more modern firmware interface. UEFI runs in 32-bit or 64-bit mode, supports the GPT partition scheme (allowing disks larger than 2 TB and up to 128 partitions), includes a standard driver model, and provides Secure Boot for verifying boot code integrity.&lt;&#x2F;p&gt;
&lt;p&gt;We will cover UEFI in detail in Article 04. But first, a brief detour to explain why the rest of this series focuses on one particular operating system.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;03b-why-linux&#x2F;&quot;&gt;Why Linux?&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Reset Vector</title>
        <published>2025-01-03T00:00:00+00:00</published>
        <updated>2025-01-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/02-the-reset-vector/"/>
        <id>https://t34ch.tech/coldboot/articles/02-the-reset-vector/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/02-the-reset-vector/">&lt;p&gt;The CPU has been released from reset. The clock is ticking. Voltages are stable. The processor is now expected to do something -- but what?&lt;&#x2F;p&gt;
&lt;p&gt;A CPU does not know what an operating system is. It does not know about hard drives, keyboards, or screens. It has no awareness of what it is or what it is supposed to do. It knows exactly one thing: an address. A specific, hardwired location in its address space where it must look for its first instruction.&lt;&#x2F;p&gt;
&lt;p&gt;That address is called the reset vector.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-an-address-space&quot;&gt;What Is an Address Space?&lt;&#x2F;h2&gt;
&lt;p&gt;Before we can talk about the reset vector, we need to talk about how a CPU sees memory. The CPU does not interact with physical RAM chips directly by name. Instead, it sees a flat, numbered sequence of memory locations called the address space.&lt;&#x2F;p&gt;
&lt;p&gt;Think of the address space as a very long row of numbered post office boxes. Box 0 is at one end. The last box is at the other. The CPU can read from or write to any box by specifying its number. That number is the address.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Address space&lt;&#x2F;strong&gt;
The complete range of memory addresses a CPU can reference. A 32-bit CPU can address 2^32 locations (4 GB). A 64-bit CPU can theoretically address 2^64 locations, though practical implementations use fewer address lines.
&lt;&#x2F;div&gt;
&lt;p&gt;On an x86 CPU (the architecture used in most PCs and servers), the address space at power-on is not what you might expect. Not every address maps to RAM. Some addresses map to ROM chips, some map to hardware device registers, and large regions may map to nothing at all.&lt;&#x2F;p&gt;
&lt;p&gt;This mapping of addresses to physical devices is called the memory map, and understanding it is essential to understanding the reset vector.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-memory-map-at-power-on&quot;&gt;The Memory Map at Power-On&lt;&#x2F;h2&gt;
&lt;p&gt;When an x86 CPU first starts, it operates in a mode called real mode. In real mode, the processor can address 1 MB of memory (addresses 0x00000 through 0xFFFFF). This is a legacy constraint inherited from the original 8086 processor from 1978, and modern CPUs maintain backward compatibility with it.&lt;&#x2F;p&gt;
&lt;p&gt;But the CPU does not start fetching instructions from the bottom of that 1 MB range. It starts from near the top.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 01 -- x86 memory map at power-on (first 1 MB)&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 400&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;400&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Memory bar --&gt;
  &lt;rect x=&quot;160&quot; y=&quot;20&quot; width=&quot;200&quot; height=&quot;360&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;!-- Regions from top to bottom --&gt;
  &lt;!-- BIOS ROM: 0xF0000 - 0xFFFFF --&gt;
  &lt;rect x=&quot;160&quot; y=&quot;20&quot; width=&quot;200&quot; height=&quot;50&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;260&quot; y=&quot;42&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot;&gt;BIOS ROM&lt;&#x2F;text&gt;
  &lt;text x=&quot;260&quot; y=&quot;58&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;64 KB&lt;&#x2F;text&gt;
  &lt;!-- Address labels right side --&gt;
&lt;p&gt;&lt;text x=&quot;375&quot; y=&quot;30&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;0xFFFFF (1 MB)&lt;&#x2F;text&gt;
&lt;line x1=&quot;360&quot; y1=&quot;25&quot; x2=&quot;370&quot; y2=&quot;25&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
&lt;text x=&quot;375&quot; y=&quot;75&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;0xF0000&lt;&#x2F;text&gt;
&lt;line x1=&quot;360&quot; y1=&quot;70&quot; x2=&quot;370&quot; y2=&quot;70&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
  &lt;!-- Video BIOS: 0xC0000 - 0xEFFFF --&gt;
  &lt;rect x=&quot;160&quot; y=&quot;70&quot; width=&quot;200&quot; height=&quot;60&quot; rx=&quot;0&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;260&quot; y=&quot;95&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot;&gt;Option ROMs&lt;&#x2F;text&gt;
  &lt;text x=&quot;260&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;(Video BIOS, etc.)&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;375&quot; y=&quot;135&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;0xC0000&lt;&#x2F;text&gt;
&lt;line x1=&quot;360&quot; y1=&quot;130&quot; x2=&quot;370&quot; y2=&quot;130&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
  &lt;!-- Upper memory: 0xA0000 - 0xBFFFF --&gt;
  &lt;rect x=&quot;160&quot; y=&quot;130&quot; width=&quot;200&quot; height=&quot;45&quot; rx=&quot;0&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;260&quot; y=&quot;155&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;Video RAM&lt;&#x2F;text&gt;
  &lt;text x=&quot;260&quot; y=&quot;168&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;128 KB&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;375&quot; y=&quot;180&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;0xA0000&lt;&#x2F;text&gt;
&lt;line x1=&quot;360&quot; y1=&quot;175&quot; x2=&quot;370&quot; y2=&quot;175&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
  &lt;!-- Conventional memory: 0x00000 - 0x9FFFF --&gt;
  &lt;rect x=&quot;160&quot; y=&quot;175&quot; width=&quot;200&quot; height=&quot;205&quot; rx=&quot;0&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;260&quot; y=&quot;260&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;12&quot;&gt;Conventional RAM&lt;&#x2F;text&gt;
  &lt;text x=&quot;260&quot; y=&quot;280&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;640 KB&lt;&#x2F;text&gt;
  &lt;text x=&quot;260&quot; y=&quot;300&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;(mostly empty at boot)&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;375&quot; y=&quot;385&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;10&quot;&gt;0x00000&lt;&#x2F;text&gt;
&lt;line x1=&quot;360&quot; y1=&quot;380&quot; x2=&quot;370&quot; y2=&quot;380&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
  &lt;!-- Left side annotations --&gt;
&lt;p&gt;&lt;text x=&quot;145&quot; y=&quot;42&quot; text-anchor=&quot;end&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;ROM&lt;&#x2F;text&gt;
&lt;text x=&quot;145&quot; y=&quot;100&quot; text-anchor=&quot;end&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;ROM&lt;&#x2F;text&gt;
&lt;text x=&quot;145&quot; y=&quot;155&quot; text-anchor=&quot;end&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;MMIO&lt;&#x2F;text&gt;
&lt;text x=&quot;145&quot; y=&quot;260&quot; text-anchor=&quot;end&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;DRAM&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Reset vector arrow --&gt;
  &lt;path d=&quot;M70,35 L155,35&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2.5&quot; marker-end=&quot;url(#arr02a)&quot;&#x2F;&gt;
  &lt;text x=&quot;60&quot; y=&quot;32&quot; text-anchor=&quot;end&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot;&gt;Reset&lt;&#x2F;text&gt;
  &lt;text x=&quot;60&quot; y=&quot;45&quot; text-anchor=&quot;end&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot;&gt;vector&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr02a&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The first 1 MB of address space on an x86 system. The BIOS ROM occupies the top 64 KB, and the CPU&#x27;s reset vector points into this region. Conventional RAM sits below, mostly empty at power-on.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The top 64 KB (addresses 0xF0000 to 0xFFFFF) is mapped to a ROM chip -- specifically, the chip that contains the BIOS firmware. Below that are option ROMs (like the video card&#x27;s built-in firmware), video memory, and then 640 KB of conventional RAM that is mostly empty at this point.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-reset-vector-on-x86&quot;&gt;The Reset Vector on x86&lt;&#x2F;h2&gt;
&lt;p&gt;On an x86 processor, the reset vector is at address &lt;strong&gt;0xFFFFFFF0&lt;&#x2F;strong&gt; -- sixteen bytes below the 4 GB boundary. Yes, you read that correctly. Even though the CPU is supposedly in real mode (which can only address 1 MB), the very first fetch after reset reaches up to the top of the 32-bit address space.&lt;&#x2F;p&gt;
&lt;p&gt;How is this possible? The answer is a quirk of x86 design. At reset, the CPU sets its code segment (CS) base to 0xFFFF0000, not the usual real-mode value. The instruction pointer (IP) is set to 0xFFF0. The combination gives a physical address of 0xFFFFFFF0. This trick allows the CPU to find the BIOS ROM, which the motherboard&#x27;s chipset maps to the top of the 4 GB address space.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Reset vector&lt;&#x2F;strong&gt;
A fixed memory address, hardwired into the CPU, that contains the first instruction to execute after a reset. On x86 processors, this address is 0xFFFFFFF0. The motherboard ensures that a ROM chip containing BIOS firmware is mapped at this address.
&lt;&#x2F;div&gt;
&lt;p&gt;The first instruction at this address is almost always a jump (JMP) instruction. It jumps to the main body of the BIOS code, which might be at a completely different address. The reset vector is just the entry point -- a signpost that says &quot;go over there to find the real startup code.&quot;&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 02 -- The first instruction fetch&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 240&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;240&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- CPU box --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;60&quot; width=&quot;140&quot; height=&quot;100&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;90&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;13&quot;&gt;CPU&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;112&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;CS:IP =&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;128&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot;&gt;FFFF:FFF0&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;148&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;= 0xFFFFFFF0&lt;&#x2F;text&gt;
  &lt;!-- Bus arrow --&gt;
  &lt;line x1=&quot;170&quot; y1=&quot;110&quot; x2=&quot;250&quot; y2=&quot;110&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr02b)&quot;&#x2F;&gt;
  &lt;text x=&quot;210&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;address bus&lt;&#x2F;text&gt;
  &lt;!-- ROM chip --&gt;
  &lt;rect x=&quot;250&quot; y=&quot;40&quot; width=&quot;180&quot; height=&quot;140&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;340&quot; y=&quot;65&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot;&gt;BIOS ROM&lt;&#x2F;text&gt;
  &lt;!-- Address cells --&gt;
  &lt;rect x=&quot;265&quot; y=&quot;78&quot; width=&quot;150&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;275&quot; y=&quot;93&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;FFF0:&lt;&#x2F;text&gt;
  &lt;text x=&quot;320&quot; y=&quot;93&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;JMP F000:E05B&lt;&#x2F;text&gt;
  &lt;rect x=&quot;265&quot; y=&quot;104&quot; width=&quot;150&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;275&quot; y=&quot;119&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;FFF5:&lt;&#x2F;text&gt;
  &lt;text x=&quot;320&quot; y=&quot;119&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;date string&lt;&#x2F;text&gt;
  &lt;rect x=&quot;265&quot; y=&quot;130&quot; width=&quot;150&quot; height=&quot;22&quot; rx=&quot;2&quot; fill=&quot;#35383C&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;text x=&quot;275&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;FFFE:&lt;&#x2F;text&gt;
  &lt;text x=&quot;320&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;model byte&lt;&#x2F;text&gt;
  &lt;!-- Jump arrow --&gt;
  &lt;path d=&quot;M430,89 C470,89 470,200 300,200 L160,200&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr02c)&quot;&#x2F;&gt;
  &lt;!-- BIOS main body --&gt;
  &lt;rect x=&quot;30&quot; y=&quot;185&quot; width=&quot;130&quot; height=&quot;40&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;95&quot; y=&quot;205&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;BIOS main code&lt;&#x2F;text&gt;
  &lt;text x=&quot;95&quot; y=&quot;218&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;at F000:E05B&lt;&#x2F;text&gt;
&lt;p&gt;&lt;text x=&quot;480&quot; y=&quot;155&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;JMP to main&lt;&#x2F;text&gt;
&lt;text x=&quot;480&quot; y=&quot;170&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;BIOS body&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr02b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr02c&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The CPU fetches its first instruction from 0xFFFFFFF0 (mapped to the BIOS ROM). That instruction is a JMP that redirects execution to the main body of the BIOS firmware.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;why-a-fixed-address&quot;&gt;Why a Fixed Address?&lt;&#x2F;h2&gt;
&lt;p&gt;Why does the CPU need a hardwired starting address? Why not let the user configure it?&lt;&#x2F;p&gt;
&lt;p&gt;The answer is simple: at the moment of reset, there is no configuration. There are no settings. There is no software running to read a configuration file. The CPU needs to start somewhere, and that somewhere must be knowable without any prior setup. A fixed address baked into the silicon is the only practical solution.&lt;&#x2F;p&gt;
&lt;p&gt;Every CPU architecture has its own reset vector:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;x86 (Intel&#x2F;AMD)&lt;&#x2F;strong&gt;: 0xFFFFFFF0&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ARM Cortex-A&lt;&#x2F;strong&gt;: 0x00000000 (or 0xFFFF0000 with high-vector configuration)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;RISC-V&lt;&#x2F;strong&gt;: Implementation-defined, commonly 0x80000000&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;MIPS&lt;&#x2F;strong&gt;: 0xBFC00000&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The address itself is arbitrary -- what matters is that the CPU designer and the board designer agree on it. The CPU will fetch from that address, and the board must ensure that a ROM containing valid code is mapped there.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The reset vector is a contract between the CPU and the motherboard. The CPU promises to fetch its first instruction from a specific address. The motherboard promises to have executable firmware at that address.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;how-the-chipset-makes-it-work&quot;&gt;How the Chipset Makes It Work&lt;&#x2F;h2&gt;
&lt;p&gt;The CPU does not physically wire itself to a ROM chip. Between the CPU and any memory or I&#x2F;O device sits the chipset -- a set of controller chips on the motherboard that routes addresses to the correct physical device.&lt;&#x2F;p&gt;
&lt;p&gt;When the CPU puts the address 0xFFFFFFF0 on its address bus, the chipset sees this address and knows it falls in the range assigned to the BIOS ROM (or, on modern systems, the SPI flash chip that contains the UEFI firmware). The chipset routes the read request to that chip, which responds with the bytes stored at that location.&lt;&#x2F;p&gt;
&lt;p&gt;This mapping is itself hardwired into the chipset. At power-on, the chipset has a default configuration that maps the top of the address space to the firmware flash chip. Later in the boot process, firmware might reconfigure the chipset to remap these regions, but at the instant of the first instruction fetch, the defaults are all that matter.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 03 -- Address routing through the chipset&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- CPU --&gt;
  &lt;rect x=&quot;230&quot; y=&quot;15&quot; width=&quot;120&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;45&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;13&quot;&gt;CPU&lt;&#x2F;text&gt;
  &lt;!-- Bus down from CPU --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;65&quot; x2=&quot;290&quot; y2=&quot;95&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- Chipset --&gt;
  &lt;rect x=&quot;190&quot; y=&quot;95&quot; width=&quot;200&quot; height=&quot;55&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;118&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot;&gt;Chipset&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;135&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Address decoder&lt;&#x2F;text&gt;
  &lt;!-- Three destination paths --&gt;
  &lt;!-- RAM path --&gt;
  &lt;line x1=&quot;230&quot; y1=&quot;150&quot; x2=&quot;100&quot; y2=&quot;210&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr02d)&quot;&#x2F;&gt;
  &lt;rect x=&quot;40&quot; y=&quot;215&quot; width=&quot;120&quot; height=&quot;45&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;100&quot; y=&quot;237&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;DRAM&lt;&#x2F;text&gt;
  &lt;text x=&quot;100&quot; y=&quot;252&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;0x0 - 0x9FFFF&lt;&#x2F;text&gt;
  &lt;!-- I&#x2F;O path --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;150&quot; x2=&quot;290&quot; y2=&quot;210&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr02e)&quot;&#x2F;&gt;
  &lt;rect x=&quot;230&quot; y=&quot;215&quot; width=&quot;120&quot; height=&quot;45&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;290&quot; y=&quot;237&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot;&gt;I&#x2F;O Devices&lt;&#x2F;text&gt;
  &lt;text x=&quot;290&quot; y=&quot;252&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;PCI, USB, etc.&lt;&#x2F;text&gt;
  &lt;!-- BIOS ROM path --&gt;
  &lt;line x1=&quot;350&quot; y1=&quot;150&quot; x2=&quot;480&quot; y2=&quot;210&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2.5&quot; marker-end=&quot;url(#arr02f)&quot;&#x2F;&gt;
  &lt;rect x=&quot;420&quot; y=&quot;215&quot; width=&quot;130&quot; height=&quot;45&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;485&quot; y=&quot;237&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot;&gt;SPI Flash&lt;&#x2F;text&gt;
  &lt;text x=&quot;485&quot; y=&quot;252&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;0xFFFFFFF0&lt;&#x2F;text&gt;
  &lt;!-- Label on BIOS path --&gt;
&lt;p&gt;&lt;text x=&quot;445&quot; y=&quot;190&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;Reset vector&lt;&#x2F;text&gt;
&lt;text x=&quot;445&quot; y=&quot;203&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;fetch goes here&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr02d&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr02e&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#00BFFF&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr02f&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The chipset decodes the address from the CPU and routes the request to the correct physical device. At reset, the address 0xFFFFFFF0 is routed to the SPI flash chip containing the BIOS&#x2F;UEFI firmware.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-cpu-s-state-at-reset&quot;&gt;The CPU&#x27;s State at Reset&lt;&#x2F;h2&gt;
&lt;p&gt;When the reset line is deasserted and the CPU begins execution, its internal state is well-defined. The x86 architecture specifies exact values for every register after reset:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CS (Code Segment)&lt;&#x2F;strong&gt;: Base = 0xFFFF0000, selector = 0xF000&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;IP (Instruction Pointer)&lt;&#x2F;strong&gt;: 0xFFF0&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;All other segment registers&lt;&#x2F;strong&gt;: Selector = 0x0000&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;General purpose registers&lt;&#x2F;strong&gt;: Most set to 0x0000&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;EFLAGS&lt;&#x2F;strong&gt;: 0x00000002 (interrupts disabled)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CR0&lt;&#x2F;strong&gt;: 0x60000010 (real mode, cache disabled)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Two things stand out in this list. First, interrupts are disabled. The CPU will not respond to hardware interrupts until firmware explicitly enables them. This makes sense -- the interrupt vector table has not been set up yet, so responding to an interrupt would cause a crash.&lt;&#x2F;p&gt;
&lt;p&gt;Second, the cache is disabled. The CPU will read directly from the ROM chip for every instruction fetch, with no caching. This is slow, but it is safe. Caching requires configuration, and no configuration has happened yet.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Real mode&lt;&#x2F;strong&gt;
The operating mode of an x86 CPU immediately after reset. In real mode, the CPU behaves like an 8086 from 1978: it uses 16-bit registers, can address 1 MB of memory, and has no memory protection. Modern operating systems switch to protected mode (32-bit) or long mode (64-bit) early in the boot process.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;no-ram-yet&quot;&gt;No RAM Yet&lt;&#x2F;h2&gt;
&lt;p&gt;Here is a detail that surprises many people: at the moment the CPU begins executing, RAM is not working.&lt;&#x2F;p&gt;
&lt;p&gt;Modern DDR memory requires initialization before it can be used. The memory controller needs to know the speed, timing, voltage, and organization of the installed DIMMs. This information is stored on a small chip on each DIMM called the SPD (Serial Presence Detect) EEPROM. The firmware must read the SPD data, configure the memory controller, and train the memory interface before a single byte of RAM is usable.&lt;&#x2F;p&gt;
&lt;p&gt;So the BIOS firmware, executing from the reset vector, must run its first instructions without any RAM. It cannot use a stack (which normally lives in RAM). It cannot store variables in RAM. It can only use CPU registers and execute directly from ROM.&lt;&#x2F;p&gt;
&lt;p&gt;This is one of the most constrained execution environments in all of computing. The firmware must bootstrap itself using only the CPU&#x27;s internal registers, reading instructions directly from the ROM chip through the chipset, until it has initialized RAM and can begin using memory normally.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
At the moment of the first instruction fetch, the CPU is running in real mode with caches disabled, interrupts off, and no usable RAM. The firmware must initialize the memory controller before it can use RAM for a stack or variables. Until then, it runs entirely from ROM using only CPU registers.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;other-architectures&quot;&gt;Other Architectures&lt;&#x2F;h2&gt;
&lt;p&gt;The x86 approach -- reset vector near the top of the address space, jump to BIOS -- is specific to x86. Other architectures handle the reset vector differently.&lt;&#x2F;p&gt;
&lt;p&gt;ARM processors typically start at address 0x00000000, where they expect to find not a single instruction but a vector table -- a series of addresses, each pointing to a handler for a different type of event (reset, undefined instruction, software interrupt, and so on). The first entry in the table is the reset vector.&lt;&#x2F;p&gt;
&lt;p&gt;RISC-V leaves the reset vector as an implementation choice. A RISC-V chip designer can put it anywhere in the address space, as long as the board maps executable firmware there. Common choices are 0x80000000 or 0x20000000.&lt;&#x2F;p&gt;
&lt;p&gt;The concept is the same everywhere: a fixed, known starting address that both the CPU and the board agree on. The specifics differ, but the principle is universal.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-vector-to-firmware&quot;&gt;From Vector to Firmware&lt;&#x2F;h2&gt;
&lt;p&gt;The reset vector is nothing more than a handoff point. It is the hardware saying to the software: &quot;You start here.&quot; What happens next -- the Power-On Self Test, hardware initialization, device enumeration -- is all firmware territory.&lt;&#x2F;p&gt;
&lt;p&gt;The CPU has done its part. It woke up, fetched its first instruction from the hardwired address, and began executing. From here, control passes to the code burned into the BIOS or UEFI firmware chip.&lt;&#x2F;p&gt;
&lt;p&gt;That firmware has a lot of work to do. It needs to test the hardware, initialize devices, configure the memory controller, set up the interrupt table, and eventually find a bootable device. All of that starts with the Power-On Self Test.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;03-post-and-the-bios&#x2F;&quot;&gt;POST and the BIOS&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Moment Power Arrives</title>
        <published>2025-01-02T00:00:00+00:00</published>
        <updated>2025-01-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/01-the-moment-power-arrives/"/>
        <id>https://t34ch.tech/coldboot/articles/01-the-moment-power-arrives/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/01-the-moment-power-arrives/">&lt;p&gt;You press the power button. A light comes on. A fan spins. Somewhere inside the case, a cascade of events begins that will end with your operating system greeting you at a login prompt. But between the moment your finger touches that button and the moment the CPU executes its very first instruction, there is an entire world of electrical engineering that most people never think about.&lt;&#x2F;p&gt;
&lt;p&gt;This article covers the first few milliseconds of that journey. No software is running yet. No code has executed. This is pure physics: electrons moving through copper, capacitors charging, voltages stabilizing, and a clock beginning to tick.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-power-button-is-not-an-on-switch&quot;&gt;The Power Button Is Not an On Switch&lt;&#x2F;h2&gt;
&lt;p&gt;The power button on a modern computer does not directly connect the power supply to the motherboard. It is a momentary switch -- press it and release it. The button sends a short signal to the motherboard&#x27;s power control circuit, which then tells the power supply to turn on.&lt;&#x2F;p&gt;
&lt;p&gt;Think of it like a doorbell. You press the button, but you are not opening the door. You are telling someone inside to open it for you.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Momentary switch&lt;&#x2F;strong&gt;
A switch that is only active while you are pressing it. Release it and the circuit opens again. The power button on your PC is a momentary switch connected to the motherboard&#x27;s front panel header.
&lt;&#x2F;div&gt;
&lt;p&gt;On ATX-standard motherboards, the power button connects two pins on the front panel header. When those pins are briefly shorted together, the motherboard&#x27;s standby power circuit sends a signal to the power supply unit (PSU) telling it to turn on. The PSU has been in standby mode this whole time -- a small 5-volt standby rail has been active since the power cable was plugged in. That standby power keeps the motherboard&#x27;s power management logic alive, waiting for your button press.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 01 -- From button press to PSU activation&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 200&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;200&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Power button --&gt;
  &lt;rect x=&quot;20&quot; y=&quot;70&quot; width=&quot;100&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;70&quot; y=&quot;100&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;Power&lt;&#x2F;text&gt;
  &lt;text x=&quot;70&quot; y=&quot;115&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;Button&lt;&#x2F;text&gt;
  &lt;!-- Arrow 1 --&gt;
  &lt;line x1=&quot;120&quot; y1=&quot;95&quot; x2=&quot;170&quot; y2=&quot;95&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr01a)&quot;&#x2F;&gt;
  &lt;text x=&quot;145&quot; y=&quot;85&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;short&lt;&#x2F;text&gt;
  &lt;!-- Front panel header --&gt;
  &lt;rect x=&quot;170&quot; y=&quot;70&quot; width=&quot;120&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;230&quot; y=&quot;95&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;Front Panel&lt;&#x2F;text&gt;
  &lt;text x=&quot;230&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot;&gt;Header (PWR)&lt;&#x2F;text&gt;
  &lt;!-- Arrow 2 --&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;95&quot; x2=&quot;340&quot; y2=&quot;95&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr01b)&quot;&#x2F;&gt;
  &lt;text x=&quot;315&quot; y=&quot;85&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;PS_ON#&lt;&#x2F;text&gt;
  &lt;!-- PSU --&gt;
  &lt;rect x=&quot;340&quot; y=&quot;50&quot; width=&quot;120&quot; height=&quot;90&quot; rx=&quot;6&quot; fill=&quot;#494D52&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;400&quot; y=&quot;80&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;Power&lt;&#x2F;text&gt;
  &lt;text x=&quot;400&quot; y=&quot;95&quot; text-anchor=&quot;middle&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;12&quot;&gt;Supply&lt;&#x2F;text&gt;
  &lt;text x=&quot;400&quot; y=&quot;115&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;+5Vsb active&lt;&#x2F;text&gt;
  &lt;!-- Arrow 3: PSU outputs --&gt;
  &lt;line x1=&quot;460&quot; y1=&quot;95&quot; x2=&quot;510&quot; y2=&quot;95&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arr01c)&quot;&#x2F;&gt;
  &lt;text x=&quot;485&quot; y=&quot;85&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;rails&lt;&#x2F;text&gt;
  &lt;!-- Voltage rails output --&gt;
  &lt;rect x=&quot;510&quot; y=&quot;60&quot; width=&quot;55&quot; height=&quot;70&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;537&quot; y=&quot;80&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;+12V&lt;&#x2F;text&gt;
  &lt;text x=&quot;537&quot; y=&quot;95&quot; text-anchor=&quot;middle&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;+5V&lt;&#x2F;text&gt;
  &lt;text x=&quot;537&quot; y=&quot;110&quot; text-anchor=&quot;middle&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;+3.3V&lt;&#x2F;text&gt;
  &lt;!-- Standby rail indicator --&gt;
  &lt;line x1=&quot;400&quot; y1=&quot;140&quot; x2=&quot;400&quot; y2=&quot;170&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot;&#x2F;&gt;
  &lt;text x=&quot;400&quot; y=&quot;185&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;+5Vsb always on when plugged in&lt;&#x2F;text&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;arr01a&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FFD700&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr01b&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#FF6600&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
    &lt;marker id=&quot;arr01c&quot; markerWidth=&quot;8&quot; markerHeight=&quot;6&quot; refX=&quot;8&quot; refY=&quot;3&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L8,3 L0,6&quot; fill=&quot;#39D353&quot;&#x2F;&gt;
    &lt;&#x2F;marker&gt;
  &lt;&#x2F;defs&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The power button shorts two pins on the front panel header. The motherboard pulls PS_ON# low, telling the PSU to activate all voltage rails.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The signal that flows from the motherboard to the PSU is called PS_ON# (the # means it is active-low -- the signal activates the PSU by being pulled to ground, not by going high). When the PSU receives this signal, it begins converting AC mains power into the DC voltages the computer needs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-voltage-rails&quot;&gt;The Voltage Rails&lt;&#x2F;h2&gt;
&lt;p&gt;A computer does not run on a single voltage. Different components need different voltages, and the PSU provides them simultaneously on separate &quot;rails.&quot; The three main rails on an ATX power supply are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;+12V&lt;&#x2F;strong&gt; -- The heavy lifter. Powers the CPU (through a separate connector), graphics card, fans, and hard drives. Most of the power budget lives here.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;+5V&lt;&#x2F;strong&gt; -- Used by USB ports, some motherboard logic, and legacy components.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;+3.3V&lt;&#x2F;strong&gt; -- Powers RAM, some chipset logic, and various low-power ICs on the motherboard.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There is also &lt;strong&gt;-12V&lt;&#x2F;strong&gt; (rarely used on modern systems, historically for serial ports) and the &lt;strong&gt;+5V standby&lt;&#x2F;strong&gt; rail we already mentioned, which stays on whenever the PSU is plugged into a wall outlet.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Voltage rail&lt;&#x2F;strong&gt;
A continuous conductor inside the power supply that carries a specific voltage to all connected components. Each rail is an independent regulated output. The &quot;+12V rail&quot; means the set of wires and traces that carry 12 volts DC throughout the system.
&lt;&#x2F;div&gt;
&lt;p&gt;When the PSU turns on, these rails do not instantly jump to their target voltages. Capacitors inside the PSU and on the motherboard need time to charge. The voltage on each rail climbs from zero toward its target over a period of milliseconds. This is called the ramp-up period.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;capacitors-and-the-ramp-up&quot;&gt;Capacitors and the Ramp-Up&lt;&#x2F;h2&gt;
&lt;p&gt;A capacitor is a component that stores electrical energy. Think of it as a small rechargeable battery that charges and discharges very quickly. Capacitors are everywhere in a computer -- on the motherboard, inside the PSU, on graphics cards, on RAM sticks.&lt;&#x2F;p&gt;
&lt;p&gt;During power-on, every capacitor in the system is discharged (assuming the machine has been off for a while). When the PSU begins outputting voltage, current flows into these capacitors, charging them. The voltage on each rail rises in a smooth curve, not a sudden jump.&lt;&#x2F;p&gt;
&lt;p&gt;This matters because digital logic circuits have minimum voltage requirements. A chip rated for 3.3V operation might malfunction if you try to run it at 2.1V. The system cannot begin operating until all voltages are stable and within specification.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 02 -- Voltage ramp-up on the +12V rail&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 250&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;250&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Axes --&gt;
  &lt;line x1=&quot;70&quot; y1=&quot;30&quot; x2=&quot;70&quot; y2=&quot;200&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;70&quot; y1=&quot;200&quot; x2=&quot;540&quot; y2=&quot;200&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Y axis labels --&gt;
&lt;p&gt;&lt;text x=&quot;60&quot; y=&quot;200&quot; text-anchor=&quot;end&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;0V&lt;&#x2F;text&gt;
&lt;text x=&quot;60&quot; y=&quot;155&quot; text-anchor=&quot;end&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;3.3V&lt;&#x2F;text&gt;
&lt;text x=&quot;60&quot; y=&quot;115&quot; text-anchor=&quot;end&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;5V&lt;&#x2F;text&gt;
&lt;text x=&quot;60&quot; y=&quot;55&quot; text-anchor=&quot;end&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;12V&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Dashed target lines --&gt;
  &lt;line x1=&quot;70&quot; y1=&quot;55&quot; x2=&quot;540&quot; y2=&quot;55&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot; opacity=&quot;0.4&quot;&#x2F;&gt;
  &lt;line x1=&quot;70&quot; y1=&quot;115&quot; x2=&quot;540&quot; y2=&quot;115&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot; opacity=&quot;0.4&quot;&#x2F;&gt;
  &lt;line x1=&quot;70&quot; y1=&quot;155&quot; x2=&quot;540&quot; y2=&quot;155&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,3&quot; opacity=&quot;0.4&quot;&#x2F;&gt;
  &lt;!-- +12V ramp curve --&gt;
  &lt;path d=&quot;M70,200 Q150,200 200,100 Q230,55 280,55 L540,55&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;545&quot; y=&quot;55&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;+12V&lt;&#x2F;text&gt;
  &lt;!-- +5V ramp curve --&gt;
  &lt;path d=&quot;M70,200 Q140,200 180,140 Q210,115 260,115 L540,115&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;545&quot; y=&quot;115&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;+5V&lt;&#x2F;text&gt;
  &lt;!-- +3.3V ramp curve --&gt;
  &lt;path d=&quot;M70,200 Q130,200 170,165 Q200,155 250,155 L540,155&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;text x=&quot;545&quot; y=&quot;155&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;+3.3V&lt;&#x2F;text&gt;
  &lt;!-- X axis labels --&gt;
&lt;p&gt;&lt;text x=&quot;70&quot; y=&quot;220&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;0ms&lt;&#x2F;text&gt;
&lt;text x=&quot;200&quot; y=&quot;220&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;5ms&lt;&#x2F;text&gt;
&lt;text x=&quot;330&quot; y=&quot;220&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;10ms&lt;&#x2F;text&gt;
&lt;text x=&quot;540&quot; y=&quot;220&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;time&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Power Good region --&gt;
  &lt;rect x=&quot;280&quot; y=&quot;25&quot; width=&quot;260&quot; height=&quot;180&quot; fill=&quot;#39D353&quot; opacity=&quot;0.05&quot;&#x2F;&gt;
  &lt;line x1=&quot;280&quot; y1=&quot;25&quot; x2=&quot;280&quot; y2=&quot;205&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot; stroke-dasharray=&quot;6,3&quot;&#x2F;&gt;
  &lt;text x=&quot;400&quot; y=&quot;235&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;PWR_OK asserted here&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;All three voltage rails ramp from 0V to their target over several milliseconds. The Power Good signal is not asserted until all rails are stable and within tolerance.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;The ramp-up is not instantaneous, and different rails stabilize at different rates. The ATX specification requires the PSU to bring all rails within tolerance before asserting a specific signal that tells the rest of the system: everything is ready.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-power-good-signal&quot;&gt;The Power Good Signal&lt;&#x2F;h2&gt;
&lt;p&gt;The PSU does not just dump voltage onto the motherboard and hope for the best. It monitors its own output. Once all voltage rails have stabilized within their specified tolerances (typically within 5% of the target voltage), the PSU asserts a signal called &lt;strong&gt;PWR_OK&lt;&#x2F;strong&gt; (also known as Power Good or PG).&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Power Good (PWR_OK)&lt;&#x2F;strong&gt;
A signal from the power supply to the motherboard indicating that all output voltages are stable and within specification. Until this signal goes high, the motherboard holds the entire system in reset.
&lt;&#x2F;div&gt;
&lt;p&gt;The ATX specification says the PSU must wait between 100 and 500 milliseconds after turning on before asserting PWR_OK. This gives capacitors time to charge and voltages time to settle.&lt;&#x2F;p&gt;
&lt;p&gt;Until PWR_OK goes high, the motherboard holds the CPU in a reset state. The CPU literally cannot do anything. It sits there, held in reset by a signal from the motherboard&#x27;s power management circuitry, waiting for permission to start.&lt;&#x2F;p&gt;
&lt;p&gt;This is a safety mechanism. If the CPU tried to execute instructions while voltages were still climbing, it would read garbage from memory, corrupt registers, and crash before it ever really started. The Power Good signal prevents that.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
The CPU does not begin executing instructions the instant you press the power button. It waits -- held in reset -- until the PSU reports that all voltages are stable. This delay is typically 100 to 500 milliseconds.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;clock-stabilization&quot;&gt;Clock Stabilization&lt;&#x2F;h2&gt;
&lt;p&gt;Digital logic does not operate continuously like an analog circuit. It operates in steps, synchronized by a clock signal. Every operation the CPU performs -- reading a value, adding two numbers, writing a result -- happens on the tick of a clock.&lt;&#x2F;p&gt;
&lt;p&gt;The motherboard has a crystal oscillator that generates this clock signal. When power first arrives, the oscillator needs time to start vibrating at a stable frequency. The first few cycles are irregular -- the frequency wobbles, the amplitude is inconsistent. This is called the oscillator startup time, and it typically takes a few milliseconds.&lt;&#x2F;p&gt;
&lt;p&gt;The CPU&#x27;s clock is derived from this base oscillator through a component called a Phase-Locked Loop (PLL). The PLL multiplies the base frequency up to the CPU&#x27;s operating frequency. A base clock of 100 MHz might be multiplied by 35 to produce a 3.5 GHz CPU clock. The PLL also needs time to lock onto the correct frequency after power arrives.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 03 -- Clock stabilization timeline&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 220&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;220&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Timeline base --&gt;
  &lt;line x1=&quot;40&quot; y1=&quot;110&quot; x2=&quot;550&quot; y2=&quot;110&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Phase labels --&gt;
  &lt;rect x=&quot;40&quot; y=&quot;25&quot; width=&quot;130&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;105&quot; y=&quot;45&quot; text-anchor=&quot;middle&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot;&gt;Unstable&lt;&#x2F;text&gt;
  &lt;rect x=&quot;170&quot; y=&quot;25&quot; width=&quot;130&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;235&quot; y=&quot;45&quot; text-anchor=&quot;middle&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot;&gt;PLL Locking&lt;&#x2F;text&gt;
  &lt;rect x=&quot;300&quot; y=&quot;25&quot; width=&quot;130&quot; height=&quot;30&quot; rx=&quot;4&quot; fill=&quot;#494D52&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;365&quot; y=&quot;45&quot; text-anchor=&quot;middle&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;Stable Clock&lt;&#x2F;text&gt;
  &lt;!-- Unstable oscillation --&gt;
  &lt;path d=&quot;M50,110 Q55,85 60,110 Q68,140 73,110 Q80,75 90,110 Q97,145 105,110 Q112,80 120,110 Q127,138 135,110 Q140,83 148,110 Q155,135 162,110&quot; fill=&quot;none&quot; stroke=&quot;#C0392B&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- PLL locking --&gt;
  &lt;path d=&quot;M170,110 Q175,88 180,110 Q185,132 190,110 Q195,90 200,110 Q205,130 210,110 Q215,92 220,110 Q225,128 230,110 Q235,93 240,110 Q245,127 250,110 Q255,94 260,110 Q265,126 270,110 Q275,95 280,110 Q285,125 290,110&quot; fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- Stable clock --&gt;
  &lt;path d=&quot;M305,110 L305,90 L315,90 L315,130 L325,130 L325,90 L335,90 L335,130 L345,130 L345,90 L355,90 L355,130 L365,130 L365,90 L375,90 L375,130 L385,130 L385,90 L395,90 L395,130 L405,130 L405,90 L415,90 L415,130 L425,130&quot; fill=&quot;none&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- Time markers --&gt;
&lt;p&gt;&lt;text x=&quot;40&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;0ms&lt;&#x2F;text&gt;
&lt;text x=&quot;170&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;~1ms&lt;&#x2F;text&gt;
&lt;text x=&quot;300&quot; y=&quot;145&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;~3ms&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Annotations --&gt;
&lt;p&gt;&lt;text x=&quot;105&quot; y=&quot;175&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Crystal oscillator&lt;&#x2F;text&gt;
&lt;text x=&quot;105&quot; y=&quot;188&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;starting up&lt;&#x2F;text&gt;
&lt;text x=&quot;235&quot; y=&quot;175&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;PLL acquiring&lt;&#x2F;text&gt;
&lt;text x=&quot;235&quot; y=&quot;188&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;frequency lock&lt;&#x2F;text&gt;
&lt;text x=&quot;365&quot; y=&quot;175&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;Clean square wave&lt;&#x2F;text&gt;
&lt;text x=&quot;365&quot; y=&quot;188&quot; text-anchor=&quot;middle&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;CPU can execute&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The crystal oscillator starts with irregular vibrations, the PLL gradually locks onto the correct frequency, and only then does the CPU have a stable clock to operate from.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;No instruction can execute until the clock is stable. The CPU needs a predictable, regular tick to synchronize its internal operations. An unstable clock would cause timing violations -- signals arriving too early or too late -- which would produce unpredictable results.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-sequence-in-full&quot;&gt;The Sequence in Full&lt;&#x2F;h2&gt;
&lt;p&gt;Let us put the whole sequence together. From the moment you press the power button to the moment the CPU is released from reset, here is what happens:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;You press the power button.&lt;&#x2F;strong&gt; The momentary switch shorts two pins on the front panel header.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;The motherboard pulls PS_ON# low.&lt;&#x2F;strong&gt; This tells the PSU to activate.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;The PSU begins converting AC to DC.&lt;&#x2F;strong&gt; Voltage rails start ramping up from zero.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Capacitors charge.&lt;&#x2F;strong&gt; Throughout the PSU and motherboard, capacitors absorb current and smooth the rising voltages.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Voltages stabilize.&lt;&#x2F;strong&gt; Each rail reaches its target and stays within tolerance.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;The crystal oscillator starts.&lt;&#x2F;strong&gt; It needs a few milliseconds to reach a stable frequency.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;The PLL locks.&lt;&#x2F;strong&gt; The CPU&#x27;s clock multiplier circuit acquires lock on the base frequency.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;The PSU asserts PWR_OK.&lt;&#x2F;strong&gt; All rails are stable. The system has permission to start.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;The motherboard releases the CPU from reset.&lt;&#x2F;strong&gt; The reset line goes inactive.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;The CPU fetches its first instruction.&lt;&#x2F;strong&gt; The boot process has begun.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This entire sequence takes somewhere between 100 milliseconds and one second. In human terms, it is the time between pressing the button and hearing the first fan spin up. In computer terms, it is an eternity -- a modern CPU could execute billions of instructions in that time, if only it were allowed to start.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Before any software runs, the hardware must complete a physical startup sequence: voltages must ramp and stabilize, the clock must lock, and the Power Good signal must be asserted. Only then is the CPU released from reset to fetch its first instruction.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;what-can-go-wrong&quot;&gt;What Can Go Wrong&lt;&#x2F;h2&gt;
&lt;p&gt;If the PSU cannot bring a voltage rail within tolerance, PWR_OK never asserts. The system stays in reset forever. From the outside, this looks like a dead computer -- you press the button, maybe a fan twitches, but nothing happens.&lt;&#x2F;p&gt;
&lt;p&gt;If PWR_OK is asserted too early (a defective or out-of-spec PSU), the CPU might start executing with unstable voltages. The result is unpredictable: it might boot and crash seconds later, it might corrupt data, or it might appear to work fine until the system is under heavy load and the marginal voltage sags below tolerance.&lt;&#x2F;p&gt;
&lt;p&gt;This is why a reliable power supply matters. The PSU is the foundation of every single thing the computer does. Every bit stored in RAM, every instruction the CPU executes, every packet sent over the network -- all of it depends on clean, stable voltage from the PSU.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-comes-next&quot;&gt;What Comes Next&lt;&#x2F;h2&gt;
&lt;p&gt;The CPU is out of reset. The clock is ticking. Voltages are stable. The processor is alive and ready to execute its first instruction.&lt;&#x2F;p&gt;
&lt;p&gt;But where does it find that first instruction? The CPU does not know what a hard drive is. It does not know about your operating system. It has no concept of files or programs. All it knows is one thing: a hardwired address in memory where it must look for its first instruction.&lt;&#x2F;p&gt;
&lt;p&gt;That address is called the reset vector, and it is the subject of the next article.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;02-the-reset-vector&#x2F;&quot;&gt;The Reset Vector&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Bits, Bytes, and Voltage</title>
        <published>2025-01-01T00:00:00+00:00</published>
        <updated>2025-01-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://t34ch.tech/coldboot/articles/00-bits-bytes-voltage/"/>
        <id>https://t34ch.tech/coldboot/articles/00-bits-bytes-voltage/</id>
        
        <content type="html" xml:base="https://t34ch.tech/coldboot/articles/00-bits-bytes-voltage/">&lt;p&gt;A computer does not think. It does not understand. It reacts to electricity. Every program you have ever run, every file you have ever saved, every pixel on your screen right now -- all of it reduces to electrical signals moving through circuits at close to the speed of light.&lt;&#x2F;p&gt;
&lt;p&gt;Before we can talk about how a computer starts up, we need to understand the language it speaks. That language has exactly two words.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;two-voltages-one-idea&quot;&gt;Two Voltages, One Idea&lt;&#x2F;h2&gt;
&lt;p&gt;Inside a modern computer, the processor and memory chips run on a supply voltage -- typically somewhere between 0.8 and 1.2 volts for a CPU core. The exact number depends on the chip, but the principle is the same everywhere.&lt;&#x2F;p&gt;
&lt;p&gt;The chip treats voltage levels as one of two states. A voltage near the supply level counts as &quot;high.&quot; A voltage near ground counts as &quot;low.&quot; Anything in between is undefined -- the hardware is not designed to work there, and if a signal lingers in that middle zone, the circuit may behave unpredictably.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Logic levels&lt;&#x2F;strong&gt;
The two defined voltage states in a digital circuit. &quot;High&quot; represents one value and &quot;low&quot; represents the other. The exact voltage thresholds depend on the chip technology, but every digital system draws the same hard line: there are exactly two valid states.
&lt;&#x2F;div&gt;
&lt;p&gt;This is not an arbitrary design choice. Engineers use two states because they are easy to distinguish electrically, even in the presence of noise, temperature drift, and manufacturing variation. A system with ten voltage levels would be more information-dense per wire, but vastly harder to build reliably. Two states give you the widest possible margin for error.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 00 -- Voltage levels in a digital circuit&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 260&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;260&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Voltage axis --&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;30&quot; x2=&quot;60&quot; y2=&quot;230&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;230&quot; x2=&quot;540&quot; y2=&quot;230&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Supply voltage line --&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;50&quot; x2=&quot;540&quot; y2=&quot;50&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;text x=&quot;45&quot; y=&quot;54&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;VCC&lt;&#x2F;text&gt;
  &lt;!-- HIGH zone --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;50&quot; width=&quot;480&quot; height=&quot;50&quot; fill=&quot;rgba(57,211,83,0.12)&quot;&#x2F;&gt;
  &lt;text x=&quot;550&quot; y=&quot;80&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;HIGH&lt;&#x2F;text&gt;
  &lt;!-- Undefined zone --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;100&quot; width=&quot;480&quot; height=&quot;80&quot; fill=&quot;rgba(192,57,43,0.12)&quot;&#x2F;&gt;
  &lt;text x=&quot;550&quot; y=&quot;145&quot; fill=&quot;#C0392B&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;UNDEFINED&lt;&#x2F;text&gt;
  &lt;!-- LOW zone --&gt;
  &lt;rect x=&quot;60&quot; y=&quot;180&quot; width=&quot;480&quot; height=&quot;50&quot; fill=&quot;rgba(0,191,255,0.12)&quot;&#x2F;&gt;
  &lt;text x=&quot;550&quot; y=&quot;210&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;LOW&lt;&#x2F;text&gt;
  &lt;!-- Ground line --&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;230&quot; x2=&quot;540&quot; y2=&quot;230&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;text x=&quot;45&quot; y=&quot;234&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;end&quot;&gt;GND&lt;&#x2F;text&gt;
  &lt;!-- Threshold lines --&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;100&quot; x2=&quot;540&quot; y2=&quot;100&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,4&quot;&#x2F;&gt;
  &lt;text x=&quot;45&quot; y=&quot;104&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;VIH&lt;&#x2F;text&gt;
  &lt;line x1=&quot;60&quot; y1=&quot;180&quot; x2=&quot;540&quot; y2=&quot;180&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;2,4&quot;&#x2F;&gt;
  &lt;text x=&quot;45&quot; y=&quot;184&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;9&quot; text-anchor=&quot;end&quot;&gt;VIL&lt;&#x2F;text&gt;
  &lt;!-- Example signal --&gt;
&lt;p&gt;&lt;polyline points=&quot;80,60 140,60 145,210 240,210 245,60 340,60 345,210 400,210 405,60 500,60&quot;
            fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2.5&quot;&#x2F;&gt;&lt;&#x2F;p&gt;
  &lt;!-- Labels --&gt;
&lt;p&gt;&lt;text x=&quot;300&quot; y=&quot;250&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;TIME&lt;&#x2F;text&gt;
&lt;text x=&quot;30&quot; y=&quot;140&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot; transform=&quot;rotate(-90 30 140)&quot;&gt;VOLTAGE&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;A digital signal swings between HIGH and LOW zones. The yellow trace shows a clean signal. The red zone in the middle is forbidden territory -- a signal that stays there produces unpredictable results.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-bit&quot;&gt;The Bit&lt;&#x2F;h2&gt;
&lt;p&gt;We call each of these two-state signals a &lt;strong&gt;bit&lt;&#x2F;strong&gt;. The word is a contraction of &quot;binary digit.&quot; A bit is the smallest possible unit of information: it distinguishes between exactly two alternatives.&lt;&#x2F;p&gt;
&lt;p&gt;By convention, we label these alternatives &lt;strong&gt;1&lt;&#x2F;strong&gt; and &lt;strong&gt;0&lt;&#x2F;strong&gt;. HIGH voltage maps to 1. LOW voltage maps to 0. But the mapping is arbitrary. Some circuits reverse it. What matters is that every conductor in a digital circuit carries exactly one bit of information at any given moment.&lt;&#x2F;p&gt;
&lt;p&gt;A single bit is not very expressive. It can represent on&#x2F;off, yes&#x2F;no, true&#x2F;false. That is all. To say anything more interesting, you need more bits.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Bit&lt;&#x2F;strong&gt;
The fundamental unit of digital information. A bit has exactly two possible values: 0 or 1. Inside the machine, each bit is a voltage level on a wire.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;counting-in-binary&quot;&gt;Counting in Binary&lt;&#x2F;h2&gt;
&lt;p&gt;When you write a number like 347 in everyday decimal notation, each digit position represents a power of ten. The 3 means &quot;three hundreds&quot; (3 x 10^2). The 4 means &quot;four tens&quot; (4 x 10^1). The 7 means &quot;seven ones&quot; (7 x 10^0).&lt;&#x2F;p&gt;
&lt;p&gt;Binary works identically, but with powers of two. Each position is worth twice as much as the one to its right.&lt;&#x2F;p&gt;
&lt;p&gt;Consider the binary number &lt;code&gt;1101&lt;&#x2F;code&gt;. Reading from right to left:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Position 0: &lt;strong&gt;1&lt;&#x2F;strong&gt; x 2^0 = 1&lt;&#x2F;li&gt;
&lt;li&gt;Position 1: &lt;strong&gt;0&lt;&#x2F;strong&gt; x 2^1 = 0&lt;&#x2F;li&gt;
&lt;li&gt;Position 2: &lt;strong&gt;1&lt;&#x2F;strong&gt; x 2^2 = 4&lt;&#x2F;li&gt;
&lt;li&gt;Position 3: &lt;strong&gt;1&lt;&#x2F;strong&gt; x 2^3 = 8&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Add them up: 8 + 4 + 0 + 1 = &lt;strong&gt;13&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;That is all binary is. The same positional number system you already know, with a smaller alphabet.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 01 -- Binary place values&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 280&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;280&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- Section 1: The 4-bit example from the text (1101 = 13) --&gt;
&lt;p&gt;&lt;text x=&quot;20&quot; y=&quot;28&quot; fill=&quot;#FFD700&quot; font-size=&quot;11&quot; font-weight=&quot;700&quot;&gt;4-BIT EXAMPLE FROM TEXT&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Column headers for 4 bits --&gt;
&lt;p&gt;&lt;text x=&quot;310&quot; y=&quot;28&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;2^3&lt;&#x2F;text&gt;
&lt;text x=&quot;390&quot; y=&quot;28&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;2^2&lt;&#x2F;text&gt;
&lt;text x=&quot;470&quot; y=&quot;28&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;2^1&lt;&#x2F;text&gt;
&lt;text x=&quot;550&quot; y=&quot;28&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;2^0&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Place values --&gt;
&lt;p&gt;&lt;text x=&quot;310&quot; y=&quot;52&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;8&lt;&#x2F;text&gt;
&lt;text x=&quot;390&quot; y=&quot;52&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;4&lt;&#x2F;text&gt;
&lt;text x=&quot;470&quot; y=&quot;52&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;2&lt;&#x2F;text&gt;
&lt;text x=&quot;550&quot; y=&quot;52&quot; fill=&quot;#00BFFF&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;line x1=&quot;290&quot; y1=&quot;62&quot; x2=&quot;570&quot; y2=&quot;62&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- 1101 = 13 --&gt;
&lt;p&gt;&lt;text x=&quot;230&quot; y=&quot;90&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;end&quot;&gt;13 =&lt;&#x2F;text&gt;
&lt;text x=&quot;310&quot; y=&quot;92&quot; fill=&quot;#FFD700&quot; font-size=&quot;26&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;390&quot; y=&quot;92&quot; fill=&quot;#FFD700&quot; font-size=&quot;26&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;470&quot; y=&quot;92&quot; fill=&quot;#8C9097&quot; font-size=&quot;26&quot; text-anchor=&quot;middle&quot;&gt;0&lt;&#x2F;text&gt;
&lt;text x=&quot;550&quot; y=&quot;92&quot; fill=&quot;#FFD700&quot; font-size=&quot;26&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;text x=&quot;250&quot; y=&quot;115&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;start&quot;&gt;8 + 4 + 0 + 1 = 13&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Divider between sections --&gt;
  &lt;line x1=&quot;20&quot; y1=&quot;135&quot; x2=&quot;560&quot; y2=&quot;135&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;1&quot; stroke-dasharray=&quot;4,4&quot;&#x2F;&gt;
  &lt;!-- Section 2: Full 8-bit examples --&gt;
&lt;p&gt;&lt;text x=&quot;20&quot; y=&quot;158&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; font-weight=&quot;700&quot;&gt;8-BIT (ONE BYTE)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Column headers: powers of two --&gt;
&lt;p&gt;&lt;text x=&quot;130&quot; y=&quot;158&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2^7&lt;&#x2F;text&gt;
&lt;text x=&quot;190&quot; y=&quot;158&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2^6&lt;&#x2F;text&gt;
&lt;text x=&quot;250&quot; y=&quot;158&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2^5&lt;&#x2F;text&gt;
&lt;text x=&quot;310&quot; y=&quot;158&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2^4&lt;&#x2F;text&gt;
&lt;text x=&quot;370&quot; y=&quot;158&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2^3&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;158&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2^2&lt;&#x2F;text&gt;
&lt;text x=&quot;490&quot; y=&quot;158&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2^1&lt;&#x2F;text&gt;
&lt;text x=&quot;550&quot; y=&quot;158&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot; text-anchor=&quot;middle&quot;&gt;2^0&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Place value row --&gt;
&lt;p&gt;&lt;text x=&quot;130&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;128&lt;&#x2F;text&gt;
&lt;text x=&quot;190&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;64&lt;&#x2F;text&gt;
&lt;text x=&quot;250&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;32&lt;&#x2F;text&gt;
&lt;text x=&quot;310&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;16&lt;&#x2F;text&gt;
&lt;text x=&quot;370&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;8&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;4&lt;&#x2F;text&gt;
&lt;text x=&quot;490&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;2&lt;&#x2F;text&gt;
&lt;text x=&quot;550&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;line x1=&quot;110&quot; y1=&quot;188&quot; x2=&quot;570&quot; y2=&quot;188&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;1&quot;&#x2F;&gt;
  &lt;!-- Example: 01000001 = 65 (ASCII &#x27;A&#x27;) --&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;216&quot; fill=&quot;#FF6600&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;65 =&lt;&#x2F;text&gt;
&lt;text x=&quot;130&quot; y=&quot;218&quot; fill=&quot;#8C9097&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;0&lt;&#x2F;text&gt;
&lt;text x=&quot;190&quot; y=&quot;218&quot; fill=&quot;#FF6600&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;250&quot; y=&quot;218&quot; fill=&quot;#8C9097&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;0&lt;&#x2F;text&gt;
&lt;text x=&quot;310&quot; y=&quot;218&quot; fill=&quot;#8C9097&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;0&lt;&#x2F;text&gt;
&lt;text x=&quot;370&quot; y=&quot;218&quot; fill=&quot;#8C9097&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;0&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;218&quot; fill=&quot;#8C9097&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;0&lt;&#x2F;text&gt;
&lt;text x=&quot;490&quot; y=&quot;218&quot; fill=&quot;#8C9097&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;0&lt;&#x2F;text&gt;
&lt;text x=&quot;550&quot; y=&quot;218&quot; fill=&quot;#FF6600&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;30&quot; y=&quot;238&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;64 + 1 = 65 (ASCII letter &quot;A&quot;)&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Example: 11111111 = 255 --&gt;
&lt;p&gt;&lt;text x=&quot;30&quot; y=&quot;264&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot; text-anchor=&quot;start&quot;&gt;255 =&lt;&#x2F;text&gt;
&lt;text x=&quot;130&quot; y=&quot;266&quot; fill=&quot;#39D353&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;190&quot; y=&quot;266&quot; fill=&quot;#39D353&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;250&quot; y=&quot;266&quot; fill=&quot;#39D353&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;310&quot; y=&quot;266&quot; fill=&quot;#39D353&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;370&quot; y=&quot;266&quot; fill=&quot;#39D353&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;430&quot; y=&quot;266&quot; fill=&quot;#39D353&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;490&quot; y=&quot;266&quot; fill=&quot;#39D353&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;text x=&quot;550&quot; y=&quot;266&quot; fill=&quot;#39D353&quot; font-size=&quot;20&quot; text-anchor=&quot;middle&quot;&gt;1&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;Top: the 4-bit example from the text -- 1101 = 13. Bottom: two full bytes. 01000001 is 65, the ASCII code for the letter &quot;A&quot;. 11111111 is 255, the largest value a single byte can hold.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;the-byte&quot;&gt;The Byte&lt;&#x2F;h2&gt;
&lt;p&gt;Eight bits grouped together form a &lt;strong&gt;byte&lt;&#x2F;strong&gt;. This is the fundamental unit of storage and data transfer in virtually every modern computer. One byte can represent 2^8 = 256 different values, numbered 0 through 255.&lt;&#x2F;p&gt;
&lt;p&gt;Why eight? Partly convention, partly practical engineering. Eight bits is enough to represent a single character in Western text (the ASCII standard uses 7 bits, with the eighth available for error checking or extensions). It divides neatly into halves (called &lt;strong&gt;nibbles&lt;&#x2F;strong&gt; -- 4 bits each), and powers of two scale cleanly: 2 bytes = 16 bits, 4 bytes = 32 bits, 8 bytes = 64 bits.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: Byte&lt;&#x2F;strong&gt;
A group of 8 bits. One byte can hold any value from 0 to 255. Almost every unit of computer storage -- kilobytes, megabytes, gigabytes -- is measured in multiples of bytes.
&lt;&#x2F;div&gt;
&lt;p&gt;The sizes you see in everyday computing are all built from bytes:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;&#x2F;th&gt;&lt;th&gt;Bytes&lt;&#x2F;th&gt;&lt;th&gt;Bits&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Byte&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Kilobyte&lt;&#x2F;td&gt;&lt;td&gt;1,024&lt;&#x2F;td&gt;&lt;td&gt;8,192&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Megabyte&lt;&#x2F;td&gt;&lt;td&gt;1,048,576&lt;&#x2F;td&gt;&lt;td&gt;8,388,608&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Gigabyte&lt;&#x2F;td&gt;&lt;td&gt;1,073,741,824&lt;&#x2F;td&gt;&lt;td&gt;8,589,934,592&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Notice these are powers of 1,024, not 1,000. That factor of 1,024 (which is 2^10) comes from the binary nature of memory addressing. A chip with 10 address lines can reach 1,024 locations. Marketing departments prefer to use 1,000 because it makes the number bigger, which is why your &quot;500 GB&quot; hard drive shows up as 465 GB in your operating system. The drive manufacturer counted in billions; the OS counts in powers of 1,024.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hexadecimal-a-shorthand-for-humans&quot;&gt;Hexadecimal: A Shorthand for Humans&lt;&#x2F;h2&gt;
&lt;p&gt;Binary numbers get long fast. The number 255 in binary is &lt;code&gt;11111111&lt;&#x2F;code&gt; -- eight characters to represent a fairly small value. For numbers in the millions, binary notation becomes unreadable.&lt;&#x2F;p&gt;
&lt;p&gt;Programmers use &lt;strong&gt;hexadecimal&lt;&#x2F;strong&gt; (base 16) as a compact way to write binary values. Hex uses sixteen symbols: 0-9 and A-F. Each hex digit represents exactly four bits -- one nibble.&lt;&#x2F;p&gt;
&lt;p&gt;This mapping is precise and mechanical:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Hex&lt;&#x2F;th&gt;&lt;th&gt;Binary&lt;&#x2F;th&gt;&lt;th&gt;Decimal&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0000&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0001&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;0010&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;0011&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;0100&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;0101&lt;&#x2F;td&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;0110&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;0111&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;1000&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;1001&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;A&lt;&#x2F;td&gt;&lt;td&gt;1010&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;B&lt;&#x2F;td&gt;&lt;td&gt;1011&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;C&lt;&#x2F;td&gt;&lt;td&gt;1100&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;D&lt;&#x2F;td&gt;&lt;td&gt;1101&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;E&lt;&#x2F;td&gt;&lt;td&gt;1110&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;F&lt;&#x2F;td&gt;&lt;td&gt;1111&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;To convert hex to binary, replace each hex digit with its four-bit equivalent. &lt;code&gt;0xFF&lt;&#x2F;code&gt; becomes &lt;code&gt;1111 1111&lt;&#x2F;code&gt;. &lt;code&gt;0x4A&lt;&#x2F;code&gt; becomes &lt;code&gt;0100 1010&lt;&#x2F;code&gt;. No arithmetic required -- just substitution.&lt;&#x2F;p&gt;
&lt;p&gt;Hex numbers are usually prefixed with &lt;code&gt;0x&lt;&#x2F;code&gt; to distinguish them from decimal. When you see &lt;code&gt;0xDEADBEEF&lt;&#x2F;code&gt; in a debugger, that is a 32-bit value: &lt;code&gt;1101 1110 1010 1101 1011 1110 1110 1111&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;logic-gates-where-meaning-begins&quot;&gt;Logic Gates: Where Meaning Begins&lt;&#x2F;h2&gt;
&lt;p&gt;Voltage levels become useful when you start combining them. A &lt;strong&gt;logic gate&lt;&#x2F;strong&gt; is a circuit that takes one or more input bits and produces an output bit according to a fixed rule.&lt;&#x2F;p&gt;
&lt;p&gt;The three fundamental gates are:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;AND&lt;&#x2F;strong&gt;: The output is 1 only if both inputs are 1. Think of two switches in series -- both must be closed for current to flow.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;OR&lt;&#x2F;strong&gt;: The output is 1 if either input (or both) is 1. Think of two switches in parallel -- either one lets current through.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;NOT&lt;&#x2F;strong&gt;: The output is the opposite of the input. One input, one output. A 1 becomes 0, a 0 becomes 1.&lt;&#x2F;p&gt;
&lt;figure&gt;
&lt;div class=&quot;diagram&quot;&gt;
&lt;div class=&quot;diagram-title&quot;&gt;Fig. 02 -- The three fundamental logic gates&lt;&#x2F;div&gt;
&lt;svg viewBox=&quot;0 0 580 320&quot; xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot;
     font-family=&quot;&#x27;IBM Plex Mono&#x27;, monospace&quot;&gt;
  &lt;rect width=&quot;580&quot; height=&quot;320&quot; fill=&quot;#35383C&quot;&#x2F;&gt;
  &lt;!-- AND Gate --&gt;
&lt;p&gt;&lt;text x=&quot;100&quot; y=&quot;30&quot; fill=&quot;#FFD700&quot; font-size=&quot;14&quot; text-anchor=&quot;middle&quot; font-weight=&quot;700&quot;&gt;AND&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- AND gate shape: flat left, curved right --&gt;
&lt;p&gt;&lt;path d=&quot;M60,50 L60,130 L100,130 Q155,130 155,90 Q155,50 100,50 Z&quot;
        fill=&quot;none&quot; stroke=&quot;#FFD700&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
&lt;text x=&quot;100&quot; y=&quot;95&quot; fill=&quot;#FFD700&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;&amp;amp;&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Inputs --&gt;
  &lt;line x1=&quot;20&quot; y1=&quot;70&quot; x2=&quot;60&quot; y2=&quot;70&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;20&quot; y1=&quot;110&quot; x2=&quot;60&quot; y2=&quot;110&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;15&quot; y=&quot;74&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;A&lt;&#x2F;text&gt;
  &lt;text x=&quot;15&quot; y=&quot;114&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;B&lt;&#x2F;text&gt;
  &lt;!-- Output --&gt;
  &lt;line x1=&quot;155&quot; y1=&quot;90&quot; x2=&quot;190&quot; y2=&quot;90&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;195&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;OUT&lt;&#x2F;text&gt;
  &lt;!-- AND truth table --&gt;
&lt;p&gt;&lt;text x=&quot;60&quot; y=&quot;160&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;A B | OUT&lt;&#x2F;text&gt;
&lt;line x1=&quot;50&quot; y1=&quot;165&quot; x2=&quot;140&quot; y2=&quot;165&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
&lt;text x=&quot;60&quot; y=&quot;178&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;0 0 |  0&lt;&#x2F;text&gt;
&lt;text x=&quot;60&quot; y=&quot;192&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;0 1 |  0&lt;&#x2F;text&gt;
&lt;text x=&quot;60&quot; y=&quot;206&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;1 0 |  0&lt;&#x2F;text&gt;
&lt;text x=&quot;60&quot; y=&quot;220&quot; fill=&quot;#FFD700&quot; font-size=&quot;10&quot;&gt;1 1 |  1&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- OR Gate --&gt;
&lt;p&gt;&lt;text x=&quot;300&quot; y=&quot;30&quot; fill=&quot;#FF6600&quot; font-size=&quot;14&quot; text-anchor=&quot;middle&quot; font-weight=&quot;700&quot;&gt;OR&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;rect x=&quot;250&quot; y=&quot;50&quot; width=&quot;100&quot; height=&quot;80&quot; rx=&quot;4&quot; fill=&quot;none&quot; stroke=&quot;#FF6600&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- Inputs --&gt;
  &lt;line x1=&quot;220&quot; y1=&quot;70&quot; x2=&quot;250&quot; y2=&quot;70&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;line x1=&quot;220&quot; y1=&quot;110&quot; x2=&quot;250&quot; y2=&quot;110&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;215&quot; y=&quot;74&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;A&lt;&#x2F;text&gt;
  &lt;text x=&quot;215&quot; y=&quot;114&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;B&lt;&#x2F;text&gt;
  &lt;!-- Output --&gt;
  &lt;line x1=&quot;350&quot; y1=&quot;90&quot; x2=&quot;390&quot; y2=&quot;90&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;395&quot; y=&quot;94&quot; fill=&quot;#39D353&quot; font-size=&quot;11&quot;&gt;OUT&lt;&#x2F;text&gt;
  &lt;!-- Label inside --&gt;
  &lt;text x=&quot;300&quot; y=&quot;95&quot; fill=&quot;#FF6600&quot; font-size=&quot;12&quot; text-anchor=&quot;middle&quot;&gt;&gt;=1&lt;&#x2F;text&gt;
  &lt;!-- OR truth table --&gt;
&lt;p&gt;&lt;text x=&quot;260&quot; y=&quot;160&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;A B | OUT&lt;&#x2F;text&gt;
&lt;line x1=&quot;250&quot; y1=&quot;165&quot; x2=&quot;340&quot; y2=&quot;165&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
&lt;text x=&quot;260&quot; y=&quot;178&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;0 0 |  0&lt;&#x2F;text&gt;
&lt;text x=&quot;260&quot; y=&quot;192&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;0 1 |  1&lt;&#x2F;text&gt;
&lt;text x=&quot;260&quot; y=&quot;206&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;1 0 |  1&lt;&#x2F;text&gt;
&lt;text x=&quot;260&quot; y=&quot;220&quot; fill=&quot;#FF6600&quot; font-size=&quot;10&quot;&gt;1 1 |  1&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- NOT Gate --&gt;
&lt;p&gt;&lt;text x=&quot;490&quot; y=&quot;30&quot; fill=&quot;#00BFFF&quot; font-size=&quot;14&quot; text-anchor=&quot;middle&quot; font-weight=&quot;700&quot;&gt;NOT&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Triangle shape --&gt;
  &lt;polygon points=&quot;440,55 540,90 440,125&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- Bubble --&gt;
  &lt;circle cx=&quot;545&quot; cy=&quot;90&quot; r=&quot;5&quot; fill=&quot;none&quot; stroke=&quot;#00BFFF&quot; stroke-width=&quot;2&quot;&#x2F;&gt;
  &lt;!-- Input --&gt;
  &lt;line x1=&quot;410&quot; y1=&quot;90&quot; x2=&quot;440&quot; y2=&quot;90&quot; stroke=&quot;#F5F5F5&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;405&quot; y=&quot;94&quot; fill=&quot;#F5F5F5&quot; font-size=&quot;11&quot; text-anchor=&quot;end&quot;&gt;A&lt;&#x2F;text&gt;
  &lt;!-- Output --&gt;
  &lt;line x1=&quot;550&quot; y1=&quot;90&quot; x2=&quot;575&quot; y2=&quot;90&quot; stroke=&quot;#39D353&quot; stroke-width=&quot;1.5&quot;&#x2F;&gt;
  &lt;text x=&quot;563&quot; y=&quot;82&quot; fill=&quot;#39D353&quot; font-size=&quot;10&quot;&gt;OUT&lt;&#x2F;text&gt;
  &lt;!-- NOT truth table --&gt;
&lt;p&gt;&lt;text x=&quot;460&quot; y=&quot;160&quot; fill=&quot;#8C9097&quot; font-size=&quot;10&quot;&gt;A | OUT&lt;&#x2F;text&gt;
&lt;line x1=&quot;450&quot; y1=&quot;165&quot; x2=&quot;520&quot; y2=&quot;165&quot; stroke=&quot;#8C9097&quot; stroke-width=&quot;0.5&quot;&#x2F;&gt;
&lt;text x=&quot;460&quot; y=&quot;178&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;0 |  1&lt;&#x2F;text&gt;
&lt;text x=&quot;460&quot; y=&quot;192&quot; fill=&quot;#00BFFF&quot; font-size=&quot;10&quot;&gt;1 |  0&lt;&#x2F;text&gt;&lt;&#x2F;p&gt;
  &lt;!-- Bottom note --&gt;
&lt;p&gt;&lt;text x=&quot;290&quot; y=&quot;260&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;Every circuit in a modern processor is built from combinations&lt;&#x2F;text&gt;
&lt;text x=&quot;290&quot; y=&quot;276&quot; fill=&quot;#8C9097&quot; font-size=&quot;11&quot; text-anchor=&quot;middle&quot;&gt;of these three operations. AND, OR, NOT -- nothing else is needed.&lt;&#x2F;text&gt;
&lt;&#x2F;svg&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;diagram-caption&quot;&gt;The three fundamental gates with their truth tables. AND requires both inputs high. OR requires at least one. NOT inverts. Every computation a CPU performs decomposes into these three operations.&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Every computation your processor performs -- addition, comparison, memory access, encryption, video decoding -- decomposes into combinations of these three operations. A modern CPU contains billions of transistors, but each transistor is acting as a switch in a logic gate. The complexity comes from composition, not from any single component.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;from-gates-to-arithmetic&quot;&gt;From Gates to Arithmetic&lt;&#x2F;h3&gt;
&lt;p&gt;You can build an adder from AND, OR, and NOT gates. To add two single-bit numbers:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;sum&lt;&#x2F;strong&gt; bit is the XOR of the two inputs (XOR is &quot;exclusive or&quot; -- true when exactly one input is 1).&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;strong&gt;carry&lt;&#x2F;strong&gt; bit is the AND of the two inputs.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;XOR itself is built from AND, OR, and NOT: &lt;code&gt;A XOR B = (A OR B) AND NOT (A AND B)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Chain eight of these single-bit adders together, feeding each carry output into the next stage&#x27;s carry input, and you have an 8-bit adder. It adds two bytes and produces a byte-sized result plus a carry flag. This is the same principle used in every ALU (arithmetic logic unit) ever built.&lt;&#x2F;p&gt;
&lt;div class=&quot;callout&quot;&gt;
&lt;strong&gt;Key term: ALU (Arithmetic Logic Unit)&lt;&#x2F;strong&gt;
The part of a processor that performs mathematical and logical operations. An ALU is built entirely from logic gates. It takes two inputs and an operation code, and produces a result. Every calculation your computer performs passes through an ALU.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;how-memory-stores-a-bit&quot;&gt;How Memory Stores a Bit&lt;&#x2F;h2&gt;
&lt;p&gt;A logic gate computes, but it does not remember. Once the input changes, the old output is gone. To store information, you need a circuit that can hold its state.&lt;&#x2F;p&gt;
&lt;p&gt;The simplest storage element is a &lt;strong&gt;latch&lt;&#x2F;strong&gt; -- two NOT gates connected in a loop. The output of the first feeds the input of the second, and the output of the second feeds back to the input of the first. This creates a stable feedback loop that holds either a 0 or a 1 indefinitely, as long as power is supplied.&lt;&#x2F;p&gt;
&lt;p&gt;Add some control gates to decide &lt;em&gt;when&lt;&#x2F;em&gt; the latch is allowed to change, and you have a &lt;strong&gt;flip-flop&lt;&#x2F;strong&gt; -- a one-bit memory cell that updates only on a clock edge. Group eight flip-flops together and you have a &lt;strong&gt;register&lt;&#x2F;strong&gt; that stores one byte. Stack millions of these cells into a grid with row and column addressing, and you have RAM.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
Every byte in your computer&#x27;s memory is a row of eight tiny circuits, each one holding a voltage level. When the power goes off, the voltage drains, and the data disappears. This is why RAM is called &quot;volatile&quot; storage -- it forgets everything the moment it loses power.
&lt;&#x2F;div&gt;
&lt;p&gt;This will matter enormously when we talk about what happens at power-on. The processor wakes up with empty RAM. Every byte reads as garbage. The machine must find its instructions from somewhere that does &lt;em&gt;not&lt;&#x2F;em&gt; forget -- and that somewhere is the subject of the next few articles.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;everything-is-a-number&quot;&gt;Everything Is a Number&lt;&#x2F;h2&gt;
&lt;p&gt;Text, images, sound, video, executable programs, network packets, encryption keys -- inside the machine, all of it is bytes. There is no difference in the hardware between a byte that represents the letter &quot;A&quot; (0x41 in ASCII), a byte that represents the color of a pixel, and a byte that is part of a machine instruction.&lt;&#x2F;p&gt;
&lt;p&gt;The meaning of a byte depends entirely on context. The value 0x41 is the letter &quot;A&quot; if a text editor reads it, the number 65 if a calculator reads it, a shade of red if a graphics program reads it, or a processor instruction (INC ECX on x86) if the CPU executes it. Same pattern of voltages. Different interpretation.&lt;&#x2F;p&gt;
&lt;p&gt;This is one of the most important ideas in computing: &lt;strong&gt;data and instructions live in the same memory, encoded the same way&lt;&#x2F;strong&gt;. The computer does not know whether a given byte is a number, a letter, or an instruction. It does whatever the program counter tells it to do with whatever bytes it finds. If the program counter points at your JPEG, the CPU will cheerfully try to execute your vacation photo. It will not end well, but nothing in the hardware prevents it.&lt;&#x2F;p&gt;
&lt;div class=&quot;remember&quot;&gt;
A computer does not understand data types. Every value in memory is just a pattern of bits. Meaning is imposed by the program that reads them. The same byte can be a number, a character, a color, or a machine instruction depending on context.
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;why-this-matters-for-cold-boot&quot;&gt;Why This Matters for Cold Boot&lt;&#x2F;h2&gt;
&lt;p&gt;When you press the power button, every piece of RAM in the system starts in an undefined state. The processor has no program loaded. There is no operating system. There are no files.&lt;&#x2F;p&gt;
&lt;p&gt;What exists is a set of circuits that can move voltages around according to fixed rules. Billions of transistors implementing AND, OR, and NOT. A bus that can carry bytes from one place to another. A small piece of non-volatile memory -- a chip that does not forget when the power goes off -- containing just enough instructions to get started.&lt;&#x2F;p&gt;
&lt;p&gt;The entire journey from power button to running operating system is the process of loading bytes into RAM, one layer at a time, each layer complex enough to load the next. Every step in that chain operates on the principles covered in this article: voltage levels, binary encoding, logic gates, and the fundamental interchangeability of data and instructions.&lt;&#x2F;p&gt;
&lt;p&gt;That is what Cold Boot is about. We start here, at the bottom, where electricity becomes information. The next article picks up the story at the exact moment you press the power button.&lt;&#x2F;p&gt;
&lt;p&gt;Next: &lt;a href=&quot;&#x2F;coldboot&#x2F;articles&#x2F;01-the-moment-power-arrives&#x2F;&quot;&gt;The Moment Power Arrives&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
