<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Shawn Anastasio</title>
    <description>A little blog showcasing some of my projects and findings over the years.
</description>
    <link>https://anastas.io/</link>
    <atom:link href="https://anastas.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 07 Apr 2021 22:08:17 +0000</pubDate>
    <lastBuildDate>Wed, 07 Apr 2021 22:08:17 +0000</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
      <item>
        <title>Debugging incorrectly closed file descriptors with LD_PRELOAD</title>
        <description>&lt;p&gt;I recently tracked down a bug in a relatively complex piece of software using the LD_PRELOAD mechanism and I
figured it was worth documenting it here in case anybody finds it useful or interesting.&lt;/p&gt;

&lt;p&gt;For those unfamiliar, &lt;a href=&quot;https://en.wikipedia.org/wiki/Dynamic_linker#Systems_using_ELF&quot;&gt;LD_PRELOAD&lt;/a&gt; is a hack
present in the dynamic linker of most unix-like systems that allows hooking calls to any functions located in a
dynamic library.  It goes without saying that this is a pretty powerful tool that can be used in many
different ways, from &lt;a href=&quot;https://github.com/wolfcw/libfaketime&quot;&gt;faking the system time&lt;/a&gt;, to &lt;a href=&quot;https://github.com/haad/proxychains&quot;&gt;forcing all network
traffic through a proxy&lt;/a&gt;, to debugging, which is what I’ll cover here.&lt;/p&gt;

&lt;h1 id=&quot;discovering-the-bug&quot;&gt;Discovering the Bug&lt;/h1&gt;

&lt;p&gt;As always, the first step in debugging is discovering an issue that you need to solve. In my case, I found an
issue while working on my &lt;a href=&quot;https://github.com/shawnanastasio/libkvmchan&quot;&gt;libkvmchan&lt;/a&gt; project, specifically its
daemon which is a multi-process multi-thread codebase with a homebrew IPC mechanism and many moving parts.&lt;/p&gt;

&lt;p&gt;After adding a slew of seemingly minor changes to the codebase, I noticed that whenever one of the newly added
codepaths was executed, statements printing to stdout would no longer make it to my console window. The
logging facility that uses stderr was unaffected, which narrowed it down. After checking the usual suspects
(missing newline to flush the buffer, print statements not being hit, etc.), I began to suspect that the
process’ stdout file descriptor had been closed somehow.&lt;/p&gt;

&lt;p&gt;To confirm my suspicion, I checked the process’ &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc&lt;/code&gt; entry, which is a kernel interface for querying
information on a running process including any file descriptors it has open.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls -l /proc/$(pgrep kvmchand)/fd
total 0
lrwx------. 1 root root 64 Apr  7 13:28 0 -&amp;gt; /dev/pts/4
lrwx------. 1 root root 64 Apr  7 13:28 2 -&amp;gt; /dev/pts/4
lrwx------. 1 root root 64 Apr  7 13:28 3 -&amp;gt; 'socket:[358583]'
lrwx------. 1 root root 64 Apr  7 14:06 4 -&amp;gt; 'anon_inode:[eventpoll]'
lrwx------. 1 root root 64 Apr  7 14:06 5 -&amp;gt; 'socket:[358585]'
lrwx------. 1 root root 64 Apr  7 14:06 7 -&amp;gt; 'socket:[358587]'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sure enough, file descriptors 0 and 2 (stdin and stderr respectively) were present and pointed to my console’s
allocated pseudo-tty, but file descriptor 1 corresponding to stdout is absent. I double checked and confirmed
that fd 1 was present before my newly-added codepath gets hit and disappears afterwards, so the issue
definitely had to do with my new code causing fd 1 to be closed.&lt;/p&gt;

&lt;p&gt;Strangely though, the new code I added had absolutely nothing to do with closing file descriptors! Grepping
the modified files for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt; calls and adding a check for file descriptor 1 didn’t catch anything either,
so it was clear that the new code was triggering a bug in an entirely different part of the codebase.&lt;/p&gt;

&lt;p&gt;So now the question is, what is the most effective way to track down the erroneous close that is occurring
in a completely unknown part of this large, multi-threaded codebase? LD_PRELOAD to the rescue!&lt;/p&gt;

&lt;h1 id=&quot;ld_preload-to-the-rescue&quot;&gt;LD_PRELOAD to the Rescue&lt;/h1&gt;

&lt;p&gt;Now that we know the bug is likely caused due to an erroneous call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt; with a file descriptor of 1, we
can discover the location of the bug rather trivially by intercepting all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt; calls with LD_PRELOAD and
checking for a parameter of fd 1.&lt;/p&gt;

&lt;p&gt;First, we create a new C file that defines a function in the global namespace with the same name and signature
as the function we want to hook. In our case, that signature is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int close(int fd)&lt;/code&gt;. Then we simply need to
inspect the argument and perform some action if it’s equal to 1, and forward it to the actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt; function
in libc otherwise.&lt;/p&gt;

&lt;p&gt;What should be done when the invalid file descriptor argument is detected though? The easiest thing I could
think of was to execute an illegal instruction which would allow us to catch the exception in a debugger.
I’m on a POWER9 system, so I used the assembly pseudo-op &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.long 0&lt;/code&gt; to do this. On x86_64 you might want to
use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int3&lt;/code&gt; instruction instead to generate a software breakpoint.&lt;/p&gt;

&lt;p&gt;Here’s the implementation of the hook:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#define _GNU_SOURCE
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;dlfcn.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close_fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close_fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;close_fn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dlsym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RTLD_NEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;close&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Tried to close fd 1 - execute an illegal instruction&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;asm&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;volatile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.long 0&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;close_fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Breaking this down, the first thing our hook does is declare a static function pointer which is used to store
the address of the actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt; function provided by our system libc. It gets populated by a call to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dlsym&lt;/code&gt; which dynamically resolves the address of the real &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt;. For more information, check out
&lt;a href=&quot;https://linux.die.net/man/3/dlsym&quot;&gt;dlsym’s man page&lt;/a&gt;, specifically the section about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RTLD_NEXT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next comes the check for file descriptor 1, which should only be hit by the bug. As discussed earlier, if the
check passes the code executes the opcode 0x00000000 which is guaranteed by the Power ISA to be an invalid
instruction and should thus raise a SIGILL. On x86_64 this should probably be replaced with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int3&lt;/code&gt; instruction.&lt;/p&gt;

&lt;p&gt;Finally we simply forward the argument to the real &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt; function and return the result.&lt;/p&gt;

&lt;p&gt;Now all that’s left is building the hook and using it to track down the bug.&lt;/p&gt;

&lt;h1 id=&quot;using-the-ld_preload-hook&quot;&gt;Using the LD_PRELOAD hook&lt;/h1&gt;

&lt;p&gt;With the hook written and saved, compiling it is straightforward - we just need to provide a few flags to gcc
telling it to output a shared library and to link against &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libdl&lt;/code&gt;, which provides the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dlsym()&lt;/code&gt; function we
used to grab the function pointer to the real &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gcc -shared -fPIC -ldl hook_close.c -o hook_close.so
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can now use LD_PRELOAD to run our application with the hook installed and then attach gdb to it:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ LD_PRELOAD=$PWD/hook_close.so ./my_application &amp;amp;
$ gdb -p $(pgrep my_application)
...
(gdb) continue
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s also possible to launch the application with the hook from within gdb:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gdb ./my_application
...
(gdb) set environment LD_PRELOAD ./hook_close.so
(gdb) run
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In my case, I went with the former method since the application I was debugging spawns multiple child
processes and it was easier to launch it normally and then attach gdb to the relevant PID.&lt;/p&gt;

&lt;p&gt;With gdb attached, it’s just a matter of triggering the bug and using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;backtrace&lt;/code&gt; command to find
the erroneous callsite:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
Thread 3 &quot;kvmchand&quot; received signal SIGILL, Illegal instruction.
Switching to Thread 0x7fff9ce4ed80 (LWP 54610)]
0x00007fffa02c0724 in close () from /home/shawnanastasio/opt/libkvmchan/hook_close.so
(gdb) backtrace
#0  0x00007fffa02c0724 in close () from /home/shawnanastasio/opt/libkvmchan/hook_close.so
#1  0x000000012702d990 in server_receiver_thread (data_=0x127050608 &amp;lt;g_ipc_data+144&amp;gt;) at daemon/ipc.c:529
#2  0x00007fff9fb59618 in start_thread () from /lib64/libpthread.so.0
#3  0x00007fff9fa68cb4 in clone () from /lib64/libc.so.6
(gdb) quit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The backtrace points to daemon/ipc.c:529 as the culprit. After observing the surrounding code the bug became
clear:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IPC_FLAG_FD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ipcmsg_send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ipc_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fd_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fail_errno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Close fds now that we're done forwarding them&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IPC_FD_MAX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This code is responsible for closing file descriptors passed via IPC messages after they have been forwarded
to their destination. The issue is that instead of iterating through the number of file descriptors present in
the array (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;msg.fd_count&lt;/code&gt;), it iterates through all values (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IPC_FD_MAX&lt;/code&gt;). This works fine if
the user always sends &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IPC_FD_MAX&lt;/code&gt; (5) file descriptors (as was the case before my recent changes), but if the user sends
less, the code will end up passing uninitialized values to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt; as long as they’re not equal to -1.&lt;/p&gt;

&lt;p&gt;In this case, it seems one of the uninitialized values of the array ended up being 1, which resulted in stdout
being closed. The fix was very straightforward to implement and was &lt;a href=&quot;https://github.com/shawnanastasio/libkvmchan/commit/8855a5680e59a2eb7b02aee6ea759b6e8e2dda36&quot;&gt;committed as 8855a5680e59&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;So what did we learn then? Well firstly, care needs to be taken when dealing with array sizes and
uninitialized values when working in C (yes, I know you already knew that), and secondly, LD_PRELOAD is
a very powerful tool that allows for tracking down some pretty nasty bugs with relatively little effort.&lt;/p&gt;

&lt;p&gt;I’m certainly not the first person to write about LD_PRELOAD debugging, but hopefully you found this 
write-up helpful or at least interesting.&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

</description>
        <pubDate>Wed, 07 Apr 2021 17:00:00 +0000</pubDate>
        <link>https://anastas.io/linux/2021/04/07/debugging-file-descriptors-ld_preload.html</link>
        <guid isPermaLink="true">https://anastas.io/linux/2021/04/07/debugging-file-descriptors-ld_preload.html</guid>
        
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>Programming a Xilinx XC9500XL CPLD with a Raspberry Pi and xc3sprog</title>
        <description>&lt;p&gt;I recently got a &lt;a href=&quot;http://dangerousprototypes.com/docs/XC9500XL_CPLD_breakout_board&quot;&gt;breakout board for the XC9572XL CPLD&lt;/a&gt;
from Dangerous Prototypes to play around with, which was particularly interesting to me because of its 5v tolerant I/O banks.
Soon after it arrived, though, I realized I didn’t have an ISE-compatible Xilinx JTAG adapter to program it, but
thankfully a number of open source solutions exist that allow you to program the device without forking over
&lt;a href=&quot;https://www.mouser.com/ProductDetail/Xilinx/HW-USB-II-G?qs=rrS6PyfT74cTrO3YL49xhw%3D%3D&quot;&gt;$270&lt;/a&gt; to Xilinx for what is
essentially a Cypress FX2 microcontroller in a red box.&lt;/p&gt;

&lt;p&gt;In this post, I’ll demonstrate how to use the &lt;a href=&quot;https://github.com/matrix-io/xc3sprog&quot;&gt;matrix-io fork of xc3sprog&lt;/a&gt; to
program the CPLD from a Raspberry Pi. It’s also worth noting that &lt;a href=&quot;https://medium.com/@jim.mussared/programming-a-xc9500xl-cpld-with-a-raspberry-pi-667dd9d6b5af&quot;&gt;others have gotten this working with OpenOCD&lt;/a&gt;,
but I’ve had the best luck with xc3sprog. It also lets you program the .jed file produced by ISE directly without any
intermediate conversion steps, which is a nice bonus.&lt;/p&gt;

&lt;h1 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h1&gt;

&lt;p&gt;You’ll just need a Raspberry Pi (any version will do, but versions &amp;lt; 4 will work best) and a CPLD with the JTAG
connection broken out. I’m using standard 2.54mm breadboard jumper wires to connect the Pi to the breakout board.
For the OS, I’m using the standard Raspberry Pi OS (formerly Raspbian) minimal image, but presumably any
Linux distro will do.&lt;/p&gt;

&lt;p&gt;You’ll also (obviously) need a .jed file produced by ISE that you want to program to the device. Getting ISE
up and running is out of the scope of this tutorial, but suffice to say it’s not a pleasant experience on
modern Linux distros.&lt;/p&gt;

&lt;h1 id=&quot;building-xc3sprog&quot;&gt;Building xc3sprog&lt;/h1&gt;

&lt;p&gt;The first step is to build xc3sprog on the Pi. There are a few dependencies which can all be obtained from Raspberry Pi OS’s
repository:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo apt-get update
$ sudo apt-get install build-essential libusb-dev libftdi-dev libgpio-dev wiringpi git cmake
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, we’ll clone xc3sprog and build it with cmake. We’re using a fork that adds support for the Pi’s native GPIO interface,
in addition to a generic linux sysfs GPIO interface (more on this later).&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git clone https://github.com/matrix-io/xc3sprog &amp;amp;&amp;amp; cd xc3sprog
$ mkdir build &amp;amp;&amp;amp; cd build
$ cmake ..
$ make
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If all goes well, you’ll have a shiny new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xc3sprog&lt;/code&gt; binary in your current working directory.&lt;/p&gt;

&lt;h1 id=&quot;wiring-the-pi-to-the-cpld&quot;&gt;Wiring the Pi to the CPLD&lt;/h1&gt;

&lt;p&gt;The next step is to physically connect the Pi’s GPIO pins to the CPLD. Surprisingly enough, I couldn’t find the actual
JTAG pinout that xc3sprog uses documented anywhere (which is part of the reason I decided to write this post and document it).
After some digging through the code, I found that the constructor for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOWiringPi&lt;/code&gt; class &lt;a href=&quot;https://github.com/matrix-io/xc3sprog/blob/master/iowiringpi.h&quot;&gt;accepts the GPIO pin numbers
used for JTAG&lt;/a&gt; and it’s called &lt;a href=&quot;https://github.com/matrix-io/xc3sprog/blob/master/iomatrixcreator.cpp&quot;&gt;here&lt;/a&gt;
for the WiringPi backend and &lt;a href=&quot;https://github.com/matrix-io/xc3sprog/blob/master/sysfscreator.cpp&quot;&gt;here&lt;/a&gt; for the sysfs backend.&lt;/p&gt;

&lt;p&gt;The choice of which backend you want to use will depend on which Raspberry Pi model you have. The WiringPi backend is much
faster but doesn’t support the Pi 4 whereas the sysfs backend works on all models but is much slower. If you have a Pi &amp;lt;= 3,
I’d recommend using the WiringPi backend. Thankfully the pinout is the same regardless of which backend you choose.&lt;/p&gt;

&lt;p&gt;Using the numbers from the constructor calls above, we can deduce the following pinout:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Signal&lt;/th&gt;
      &lt;th&gt;GPIO&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;TMS&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TCK&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TDI&lt;/td&gt;
      &lt;td&gt;22&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TDO&lt;/td&gt;
      &lt;td&gt;27&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Note that these are &lt;strong&gt;GPIO pin numbers&lt;/strong&gt; and don’t correspond to the pin numbers of the Raspberry Pi’s expansion header.&lt;/p&gt;

&lt;p&gt;We can see how these GPIO pin numbers correspond to pins on the expansion header in this image:&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;
&lt;img src=&quot;/assets/raspi-gpio.png&quot; /&gt;
&lt;figcaption&gt;Image CC BY-SA Raspberry Pi Foundation: https://www.raspberrypi.org/documentation/usage/gpio&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This means that JTAG signals should be connected to the following expansion header pins&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Signal&lt;/th&gt;
      &lt;th&gt;GPIO&lt;/th&gt;
      &lt;th&gt;Header Pin&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;TMS&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;7&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TCK&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TDI&lt;/td&gt;
      &lt;td&gt;22&lt;/td&gt;
      &lt;td&gt;15&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;TDO&lt;/td&gt;
      &lt;td&gt;27&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;After wiring these up in addition to a ground pin (and an appropriate voltage pin if you’re powering the CPLD from the Pi), we can
finally use xc3sprog to program the device.&lt;/p&gt;

&lt;h1 id=&quot;programming-the-cpld&quot;&gt;Programming the CPLD&lt;/h1&gt;

&lt;p&gt;With the Pi set up, the next thing to do is see if xc3sprog can detect the CPLD on the JTAG bus:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./xc3sprog -c &amp;lt;backend&amp;gt; -j
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;backend&amp;gt;&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;matrix_creator&lt;/code&gt; for the WiringPi backend or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sysfsgpio_creator&lt;/code&gt; for the sysfs one.&lt;/p&gt;

&lt;p&gt;If all goes well, you should see something like this:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;JTAG loc.:   0  IDCODE: 0x59604093  Desc:                       XC9572XL Rev: E  IR length:  8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We can see that my CPLD was detected at JTAG location 0. If you don’t see anything, double check your wiring.&lt;/p&gt;

&lt;p&gt;To program a .jed file now, all we need to do is pass it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xc3sprog&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./xc3sprog -c &amp;lt;backend&amp;gt; -p &amp;lt;JTAG location from above&amp;gt; -v &amp;lt;path/to/file.jed&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;/assets/cpld-xc3sprog.gif&quot; alt=&quot;&quot; /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

&lt;style&gt;

figure {
    display: inline-block;
    margin: 20px;
}
figure img {
    vertical-align: top;
}
figure figcaption {
    text-align: center;
}

// Table style from: https://gist.github.com/andyferra/2554919

p, blockquote, ul, ol, dl, li, table, pre {
  margin: 15px 0; }

table {
  padding: 0; }
  table tr {
    border-top: 1px solid #cccccc;
    background-color: white;
    margin: 0;
    padding: 0; }
    table tr:nth-child(2n) {
      background-color: #f8f8f8; }
    table tr th {
      font-weight: bold;
      border: 1px solid #cccccc;
      text-align: left;
      margin: 0;
      padding: 6px 13px; }
    table tr td {
      border: 1px solid #cccccc;
      text-align: left;
      margin: 0;
      padding: 6px 13px; }
    table tr th :first-child, table tr td :first-child {
      margin-top: 0; }
    table tr th :last-child, table tr td :last-child {
      margin-bottom: 0; }

&lt;/style&gt;

</description>
        <pubDate>Tue, 29 Sep 2020 17:00:00 +0000</pubDate>
        <link>https://anastas.io/hardware/2020/09/29/xc9500-cpld-raspberry-pi-xc3sprog.html</link>
        <guid isPermaLink="true">https://anastas.io/hardware/2020/09/29/xc9500-cpld-raspberry-pi-xc3sprog.html</guid>
        
        
        <category>hardware</category>
        
      </item>
    
      <item>
        <title>Running a mainline linux kernel on the NVIDIA Jetson Xavier AGX</title>
        <description>&lt;p&gt;The &lt;a href=&quot;https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-agx-xavier/&quot;&gt;Jetson Xavier AGX&lt;/a&gt;
is an embedded ARM64 linux platform from NVIDIA with pretty impressive specifications and a decent software ecosystem.
Most users will probably be using the NVIDIA-provided &lt;a href=&quot;https://developer.nvidia.com/embedded/linux-tegra&quot;&gt;Linux4Tegra&lt;/a&gt; (L4T)
distribution on their Xaviers, which comes with a laughably ancient 4.9 kernel build and quite a few out-of-tree drivers.
This means users will miss out on new features, upstream driver additions, and security fixes from the upstream Linux
kernel project.&lt;/p&gt;

&lt;p&gt;Thankfully though, support for the Xavier SoC and a lot of its peripherals are present in recent Linux releases, so running
a mainline kernel is possible (though NVIDIA’s documentation certainly won’t tell you how). Below we’ll walk through
the process of compiling a kernel from mainline sources and booting it on the Xavier.&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To perform the whole operation, you’ll need a few prerequisites.&lt;/p&gt;

&lt;h1 id=&quot;kernel-sources&quot;&gt;Kernel Sources&lt;/h1&gt;
&lt;p&gt;We’ll start off by downloading the mainline kernel sources we wish to compile, as well as some build prerequisites.&lt;/p&gt;

&lt;p&gt;On Ubuntu 18.04, you can download the build requisites with the following:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo apt-get install build-essential libncurses-dev bison flex libssl-dev libelf-dev gcc-aarch64-linux-gnu
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, you’ll need to grab a copy of the kernel sources you want to compile. For this tutorial we’ll download straight
from git.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;nvidia-jetpack-sdk&quot;&gt;Nvidia Jetpack SDK&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.nvidia.com/embedded/jetpack&quot;&gt;Jetpack&lt;/a&gt; is NVIDIA’s SDK that comes with everything you’ll need to
flash the Xavier. Unfortunately, many of the tools it ships seem to be proprietary binaries, so you’ll need to
do this on an x86_64 machine.&lt;/p&gt;

&lt;p&gt;The easiest way to get Jetpack set up is with the &lt;a href=&quot;https://developer.nvidia.com/nvsdk-manager&quot;&gt;NVIDIA SDK Manager&lt;/a&gt;.
You’ll need to make an NVIDIA Developer account to download it unfortunately.&lt;/p&gt;

&lt;p&gt;Once you’ve got the SDK Manager, click through and download the latest Jetpack release (4.4 at the time of writing)
for the Xavier AGX. I’d also recommend un-checking the Host Machine software selector which will install a bunch
of unnecessary NVIDIA stuff to your host machine.&lt;/p&gt;

&lt;p&gt;Finally, follow the directions to flash the included L4T release to your Xavier. We’ll use L4T as the base distro which
we’ll install our mainline kernel build over. See &lt;a href=&quot;https://docs.nvidia.com/sdk-manager/install-with-sdkm-jetson/index.html&quot;&gt;here&lt;/a&gt;
for more information on using the SDK Manager.&lt;/p&gt;

&lt;h2 id=&quot;building-the-kernel&quot;&gt;Building the kernel&lt;/h2&gt;
&lt;p&gt;With the prerequisites out of the way, we can begin building the kernel. Change to the directory where you downloaded
the kernel sources and begin the configuration process:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd linux
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the menuconfig interface, enable the ethernet driver under:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Device Drivers -&amp;gt; Network device support -&amp;gt; Ethernet driver support
    -&amp;gt; STMicroelectronics devices
        -&amp;gt; STMicroelectronics Multi-Gigabit Ethernet driver
            -&amp;gt; STMMac Platform bus support
                -&amp;gt; Support for snps,dwc-qos-ethernet.txt DT binding
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Be sure to enable support for any other peripherals or features you’ll use.&lt;/p&gt;

&lt;p&gt;After the configuration’s done, you can launch the build:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j`nproc`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This will launch one build for every logical core on your machine. Change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-j&lt;/code&gt; parameter if you want something else.&lt;/p&gt;

&lt;p&gt;If all goes well, the build will complete successfully and you can move on to the next step.&lt;/p&gt;

&lt;h1 id=&quot;installing-the-kernel&quot;&gt;Installing the kernel&lt;/h1&gt;
&lt;p&gt;With the kernel built, the next step is to install it to your Xavier’s root filesystem, along with an initramfs
and bootloader configuration. The easiest way to accomplish this is to simply copy over the kernel build directory
to your Xavier and run the make install targets there.&lt;/p&gt;

&lt;p&gt;It’s worth nothing that there are other ways of accomplishing this, like using qemu-aarch64 with binfmt-misc
to chroot into the L4T rootfs and installing there. Advanced techniques like that are out of the scope of this
tutorial though, so we’ll continue on by copying the built source to an up-and-running Xavier.&lt;/p&gt;

&lt;p&gt;Copying the build directory can be easily accomplished &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsync&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ rsync -azP ../linux &amp;lt;xavier_user&amp;gt;@&amp;lt;xavier_ip&amp;gt;:~/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Substitute your Xavier’s username and IP address.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, log in to the Xavier and execute the following commands to install the kernel&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd linux
$ sudo make modules_install
$ sudo make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, add an entry for the kernel in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/boot/extlinux/extlinux.conf&lt;/code&gt;, substituting kernel and initramfs names:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LABEL mainline
      MENU LABEL mainline kernel
      LINUX /boot/vmlinuz-5.7.0-rc7-vanilla-00212-gbdc48fa11e46
      INITRD /boot/initrd.img-5.7.0-rc7-vanilla-00212-gbdc48fa11e46
      APPEND ${cbootargs}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With the kernel installed, all that’s left is to flash the mainline device tree before we can boot it.&lt;/p&gt;

&lt;h1 id=&quot;flashing-the-device-tree&quot;&gt;Flashing the device tree&lt;/h1&gt;
&lt;p&gt;One major way difference between L4T’s kernel 4.9 fork and mainline is the layout of the Xavier’s device tree.
This has the unfortunate effect of making mainline kernels unbootable with L4T device trees and vice versa.&lt;/p&gt;

&lt;p&gt;On many embedded linux systems, the device tree is simply stored as a normal file that can be read by
the bootloader, just like the kernel. Unfortunately for us, the Xavier does things a bit differently.&lt;/p&gt;

&lt;p&gt;With the default bootloader provided with L4T, the Xavier loads its device tree from a special partition
on internal flash memory. This means that replacing the device tree requires using Jetpack’s flashing tools
from an x86_64 machine.&lt;/p&gt;

&lt;p&gt;To get started, head back to your x86_64 machine, and navigate to the Jetpack installation directory.
If you used the NVIDIA SDK Manager, that path will probably be something like:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;~/nvidia/nvidia_sdk/JetPack_4.4_DP_Linux_DP_JETSON_AGX_XAVIER/Linux_for_Tegra
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From here, we’re going to copy the jetson-xavier configuration and modify it to point to the mainline
kernel’s device tree, instead of the L4T one.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cp jetson-xavier.conf jetson-xavier-mainline.conf
$ vi jetson-xavier-mainline.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Append the following line to the end of the file:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;DTB_FILE=tegra194-p2972-0000.dtb;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then, save and exit your editor.&lt;/p&gt;

&lt;p&gt;Now we need to copy the device tree produced by the linux build into the L4T directory. Assuming your
linux tree is at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/linux&lt;/code&gt;, execute the following:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cp ~/linux/arch/arm64/boot/dts/nvidia/tegra194-p2972-0000.dtb kernel/dtb/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we’re ready to flash the device tree. Put your Xavier into RCM mode by holding down the middle
button while turning it on (left button) or resetting (right button), and enter the following command:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo ./flash.sh -r -k kernel-dtb jetson-xavier-mainline mmcblk0p1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will read in the new device tree and flash it to the device.&lt;/p&gt;

&lt;p&gt;If all goes well, the device should reboot and you will be able to select your mainline kernel
build from the extlinux boot menu.&lt;/p&gt;
</description>
        <pubDate>Mon, 01 Jun 2020 17:00:00 +0000</pubDate>
        <link>https://anastas.io/embedded/linux/2020/06/01/mainline-linux-xavier.html</link>
        <guid isPermaLink="true">https://anastas.io/embedded/linux/2020/06/01/mainline-linux-xavier.html</guid>
        
        
        <category>embedded</category>
        
        <category>linux</category>
        
      </item>
    
      <item>
        <title>OSDEV: Implementing a basic x86 page frame allocator in C</title>
        <description>&lt;p&gt;When writing an operating system for any architecture, one of the most important
functions you’ll have to write is the page frame allocator. The page frame allocator allows the OS
to divide the physical memory available on a system into chunks called page frames,
which can then be used later to allocate memory to applications with a separate
paging function.&lt;/p&gt;

&lt;p&gt;There are many methods of page frame allocation, each with varying levels of
complexity and efficiency. For an overview of many of these methods, see the
&lt;a href=&quot;http://wiki.osdev.org/Page_Frame_Allocation&quot;&gt;OSDev Wiki&lt;/a&gt;. In this post we’ll be
going over a much less efficient method than those outlined in the wiki for simplicity’s
sake, but you can improve upon it later.&lt;/p&gt;

&lt;p&gt;Unlike those outlined in the wiki, our page frame allocator isn’t actually going
to be storing any data of its own. Instead, we’re going to piggyback off of
the Multiboot information structure. If you’re following this tutorial, you
hopefully already have a basic Multiboot kernel set up, as well as a basic
understanding of the Multiboot specification (the PDF for which can be found
&lt;a href=&quot;https://www.gnu.org/software/grub/manual/multiboot/multiboot.pdf&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Without reading the entire specification, the rundown is that your Multiboot-compliant
bootloader (probably GRUB) will provide you with an information structure that contains
a lot data about the system you’re running on. Among this data is the Multiboot
memory map, which provides a listing of all memory regions in the system, and
which ones you’re allowed to write to (many regions are reserved for things like
VGA video output).&lt;/p&gt;

&lt;p&gt;To access this memory map, we must first pass a pointer to the information structure
to our kernel’s entry point. Luckily, our bootloader will put this pointer in the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebx&lt;/code&gt; register when we first boot up, so all we have to do is pass it as a parameter
to our entrypoint in assembly. Along with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ebx&lt;/code&gt;, we’ll also pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eax&lt;/code&gt; which contains
a “magic value”, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x2BADB002&lt;/code&gt;, which you can use to verify that the bootloader is
in fact Multiboot-compliant.&lt;/p&gt;

&lt;h2 id=&quot;getting-the-multiboot-information-structure&quot;&gt;Getting the Multiboot information structure&lt;/h2&gt;
&lt;p&gt;Before we start, we have to make sure that we’ve declared to our bootloader
that we want the memory map to be included in the information structure, as it is
optional by default. If you’re using the boot assembly code from the
&lt;a href=&quot;http://wiki.osdev.org/Bare_Bones&quot;&gt;OSDev Bare Bones&lt;/a&gt; tutorial, this is already done for you.
The code to specify we want the memory map looks like this (at the top of your file):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-nasm&quot; data-lang=&quot;nasm&quot;&gt;&lt;span class=&quot;no&quot;&gt;MEMINFO&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;     equ&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;; You can add more flags here separated by |&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;FLAGS&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;       equ&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;MEMINFO&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;MAGIC&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;       equ&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1BADB002&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;CHECKSUM&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;    equ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;MAGIC&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;FLAGS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nf&quot;&gt;.section&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;multiboot&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;align&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;MAGIC&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;FLAGS&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;dd&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;CH&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ECKSUM&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’ll also have to make sure that the initial stack is at least 4096 bytes
(the size of a single page). As with the previous step, if you’re using the
OSDev Bare Bones code this is done already. I’ll be setting it to 16384 bytes,
but anything greater than 4096 bytes should suffice.
This change needs to be done in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boot.asm&lt;/code&gt; or equivalent file.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-nasm&quot; data-lang=&quot;nasm&quot;&gt;&lt;span class=&quot;nf&quot;&gt;section&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;.bootstrap_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nobits&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;align&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;stack_bottom:&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;resb&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16384&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;stack_top:&lt;/span&gt;

&lt;span class=&quot;nf&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;nf&quot;&gt;section&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;.text&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_start&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;_start:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; Use the stack we allocated above&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;mov&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;stack_top&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;; Ensure stack is 16-bit aligned&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now that our stack is big enough, we can pass the Multiboot information structure
as well as the magic value to our kernel entrypoint. Remember that we must push the
values in the reverse order that we want to use them:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-nasm&quot; data-lang=&quot;nasm&quot;&gt;&lt;span class=&quot;nf&quot;&gt;section&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;.text&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_start&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;_start:&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;; Push Multiboot information structure&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ebx&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;; Push Multiboot magic value&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;push&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eax&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;; Call our kernel entrypoint&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;kernel_main&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we can access these values in our kernel’s C entrypoint, we just have to
change its parameters:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;kernel_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mboot_magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;defining-the-multiboot-information-structure&quot;&gt;Defining the Multiboot information structure&lt;/h2&gt;
&lt;p&gt;To read the Multiboot information structure, we first need to declare a few
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt;s in C that define its layout. Luckily the aforementioned
&lt;a href=&quot;https://www.gnu.org/software/grub/manual/multiboot/multiboot.pdf&quot;&gt;Multiboot specification PDF&lt;/a&gt; has them written out for you on page 16.
While it does declare more than we’ll need for this tutorial, it’s not a bad idea
to include the whole file anyways as it may be useful in the future.&lt;/p&gt;

&lt;p&gt;Once you have the structures and constants from the PDF included into your kernel,
there’s one more thing we need to do before we can start parsing the information
structure.&lt;/p&gt;

&lt;h2 id=&quot;validating-the-multiboot-magic-value&quot;&gt;Validating the Multiboot magic value&lt;/h2&gt;
&lt;p&gt;As stated before, the Multiboot magic value is simply a constant that all
Multiboot-compliant bootloaders will provide to prove that they are compliant.
Before we even attempt to read the Multiboot information structure, we should
verify this value so that we don’t try to read garbage in the event that the kernel
is not booted properly.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;kernel_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mboot_magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// MULTIBOOT_BOOTLOADER_MAGIC is defined on page 16 of the PDF too&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_magic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MULTIBOOT_BOOTLOADER_MAGIC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// If the magic is wrong, we should probably halt the system.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Error: We weren't booted by a compliant bootloader!&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;preparing-to-read-the-multiboot-information-structure&quot;&gt;Preparing to read the Multiboot information structure&lt;/h2&gt;
&lt;p&gt;Now that we’ve verified the magic value, we can read the Multiboot information structure
and look for the memory map. As it’s possible the memory map wasn’t included
(in the case of an incomplete bootloader or other error), it’s always good to
check for its existence.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;kernel_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mboot_magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// First, cast the pointer to a multiboot_info_t struct pointer&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;multiboot_info_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mboot_hdr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;multiboot_info_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// The specification states that bit 6 signifies the presence of the memory map&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// We can check the header flags to see if it's there&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// The memory map is not present, we should probably halt the system&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Error: No Multiboot memory map was provided!&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’re almost there, but first, let’s set some global variables that will help us
keep track of things and make our lives easier.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * At the top of your file, we'll make some global variables that will help us
 * keep track of frames. I'll explain what these do in a bit.
 */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;multiboot_info_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;verified_mboot_hdr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mboot_reserved_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mboot_reserved_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next_free_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;kernel_main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mboot_magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;cm&quot;&gt;/**
     * After we've verified the information structure, let's update our
     * global variables.
     */&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;verified_mboot_hdr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mboot_hdr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mboot_reserved_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_hdr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mboot_reserved_end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mboot_hdr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;multiboot_info_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;next_free_frame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, we’ve made quite a few variables. First, we’ve got a pointer,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;verified_mboot_hdr&lt;/code&gt; where we can store our pointer to the information structure
so other functions can access it easily. Next, we’ve got &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mboot_reserved_start&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mboot_reserved_end&lt;/code&gt; which, surprisingly enough, store the start and end
locations of the Multiboot information structure in memory so we don’t accidentally
overwrite it later. Finally, we’ve got &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next_free_frame&lt;/code&gt;, which stores the number
of the next free frame. This will be explained in greater detail in a later section.&lt;/p&gt;

&lt;h2 id=&quot;a-page-frame-allocator&quot;&gt;A page frame allocator&lt;/h2&gt;
&lt;p&gt;We’ve gone through all the steps to verify and prepare to read the Multiboot
information structure, but up until now you didn’t know why. As stated before,
our page frame allocator is going to piggyback off of the Multiboot memory map
to keep track of allocated frames. We’re going to do this by having a single
counter that increases by one every time we allocate a 4096 chunk (frame) of free memory
in the Multiboot memory map from start to end. This way, frame #1 is always the
first 4096 bytes marked as free in the memory map, #2 is the second 4096 bytes,
and so on. This is what the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next_free_frame&lt;/code&gt; variable in the previous section is
for.&lt;/p&gt;

&lt;p&gt;Before we can write the actual allocator, we need a method to read the memory map
and retrieve memory addresses that correspond to frame numbers, and vice versa.
For this we’re going to create a separate function that accesses those varibles
we created earlier.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#define MMAP_GET_NUM 0
#define MMAP_GET_ADDR 1
#define PAGE_SIZE 4096
&lt;/span&gt;
&lt;span class=&quot;cm&quot;&gt;/**
 * A function to iterate through the multiboot memory map.
 * If `mode` is set to MMAP_GET_NUM, it will return the frame number for the
 * frame at address `request`.
 * If `mode` is set to MMAP_GET_ADDR, it will return the starting address for
 * the frame number `request`.
 */&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mmap_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// We're reserving frame number 0 for errors, so skip all requests for 0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// If the user specifies an invalid mode, also skip the request&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MMAP_GET_NUM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MMAP_GET_ADDR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Increment through each entry in the multiboot memory map&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uintptr_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_mmap_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uintptr_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;verified_mboot_hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mmap_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uintptr_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mmap_end_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_mmap_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;verified_mboot_hdr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mmap_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cur_mmap_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mmap_end_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Get a pointer to the current entry&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;multiboot_memory_map_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_entry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
                                        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;multiboot_memory_map_t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cur_mmap_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Now let's split this entry into page sized chunks and increment our&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// internal frame number counter&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_entry_end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PAGE_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_entry_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PAGE_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MMAP_GET_NUM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PAGE_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// If we're looking for a frame number from an address and we found it&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// return the frame number&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// If the requested chunk is in reserved space, skip it&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MULTIBOOT_MEMORY_RESERVED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MMAP_GET_ADDR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;c1&quot;&gt;// The address of a chunk in reserved space was requested&lt;/span&gt;
                    &lt;span class=&quot;c1&quot;&gt;// Increment the request until it is no longer reserved&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// Skip to the next chunk until it's no longer reserved&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MMAP_GET_ADDR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// If we're looking for a frame starting address and we found it&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// return the starting address&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Increment by the size of the current entry to get to the next one&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;cur_mmap_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uintptr_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// If no results are found, return 0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;While this code looks daunting, the basic concept behind it is quite simple.
It essentially does the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Read each entry in the memory map&lt;/li&gt;
  &lt;li&gt;Split each entry into frame-sized chunks (4096 bytes)&lt;/li&gt;
  &lt;li&gt;Iterate through each chunk until a valid address is found for the given frame number
or a frame number is found for the given address.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we can read the memory map, creating an allocator can be done quite
simply:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Allocate the next free frame and return it's frame number
 */&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;allocate_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Get the address for the next free frame&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mmap_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next_free_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MMAP_GET_ADDR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Verify that the frame is not in the multiboot reserved area&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// If it is, increment the next free frame number and recursively call back.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;multiboot_reserved_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;multiboot_reserved_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next_free_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allocate_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Call mmap_read again to get the frame number for our address&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mmap_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cur_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MMAP_GET_NUM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Update next_free_frame to the next unallocated frame number&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;next_free_frame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Finally, return the newly allocated frame num&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, to allocate a page frame you simply have to call&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_frame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allocate_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_frame_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mmap_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MMAP_GET_ADDR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;New frame allocated at: 0x%x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_frame_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations! You now have a working (albeit primitive) method of page frame
allocation for your operating system. It cannot yet free frames, but it provides
a good starting point for developing a paging system. In the future, I may write
another post improving upon this allocator with freeing implemented, as well as
some performance enhancements.&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;p&gt;If you get stuck anywhere, I recommend taking a peek at my example OS
&lt;a href=&quot;https://github.com/shawnanastasio/ShawnOS&quot;&gt;ShawnOS&lt;/a&gt;, as well as the plethora
of online resources related to OS development, such as the
&lt;a href=&quot;http://wiki.osdev.org/&quot;&gt;OSDev Wiki&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Mon, 08 Aug 2016 21:42:10 +0000</pubDate>
        <link>https://anastas.io/osdev/memory/2016/08/08/page-frame-allocator.html</link>
        <guid isPermaLink="true">https://anastas.io/osdev/memory/2016/08/08/page-frame-allocator.html</guid>
        
        
        <category>osdev</category>
        
        <category>memory</category>
        
      </item>
    
  </channel>
</rss>
