Jekyll2023-01-04T11:23:07+00:00https://tix3dev.github.io//feed.xmlTix3Dev’s BlogA personal blog about all kinds of nerdy stuff :DYves VollmeierapoptOS-Series-1: Introduction2022-06-06T00:00:00+00:002022-06-06T00:00:00+00:00https://tix3dev.github.io//apoptos-series-1<h2 id="foreword">Foreword</h2>
<p>Whether or not you already are familiar with apoptOS, this blog post will talk about the project itself and what you can expect from this series. Enjoy the ride!</p>
<h2 id="what-is-apoptos">What is apoptOS?</h2>
<p><a href="https://github.com/Tix3Dev/apoptOS">apoptOS</a> an open source project currently only developed by myself, Yves Vollmeier aka Tix3Dev. It’s a modern x86_64 UNIX-like microkernel-based operating system written in C and Assembly. The main purpose of it in general is to help me understand computers better whilst having fun, as I like building stuff :D</p>
<p>Especially I want to understand the following topics better:</p>
<ul>
<li>Microkernels</li>
<li>UNIX-like systems</li>
<li>Scheduling</li>
<li>Messaging (IPC)</li>
<li>Syscalls</li>
<li>Userland</li>
<li>ELF</li>
<li>Filesystems</li>
</ul>
<h2 id="what-is-this-series-about">What is this series about?</h2>
<p>In this series of blog posts, I will document milestones regarding the development of apoptOS and my learning process. This will include the topics mentioned above.</p>
<p><em>NOTE: All the blog posts are treated as snapshots in time, meaning I won’t update e.g. a list of features currently available.</em></p>
<h2 id="next">Next</h2>
<p><a href="https://tix3dev.github.io/apoptos-series-2">Milestone - Memory management</a></p>Yves VollmeierForeword Whether or not you already are familiar with apoptOS, this blog post will talk about the project itself and what you can expect from this series. Enjoy the ride!apoptOS-Series-2: Milestone - Memory management2022-06-06T00:00:00+00:002022-06-06T00:00:00+00:00https://tix3dev.github.io//apoptos-series-2<h2 id="foreword">Foreword</h2>
<p>In this blog post I will talk about the concepts for memory management in apoptOS and how to use them.</p>
<h2 id="physical-memory-management">Physical memory management</h2>
<p>Generally speaking, this part is in charge of managing actual memory in RAM, i.e. the addresses used here directly correspond to memory in RAM. In order to manage that kind of memory, physical memory, we need to know how the bootloader, <a href="https://github.com/limine-bootloader/limine">Limine</a>, set up the memory map. To get this information, we can use the <code class="language-plaintext highlighter-rouge">stivale2_struct_tag_memmap</code> struct provided by the <a href="https://github.com/stivale/stivale">stivale2 boot protocol</a>.</p>
<h3 id="bitmap-based-page-frame-allocator">Bitmap based page frame allocator</h3>
<p>Now that we know where the usable entries / memory locations are, we can store those informations in a data structure. apoptOS makes use of a bitmap (hence the name bitmap based allocator), where each bit in the bitmap corresponds to a page / block of memory (hence the name page frame allocator) through a mapping system. The value of a bit says if it’s corresponding page is free or used. Note that in apoptOS pages are 4 KiB in size.</p>
<p>Before we can allocate or free anything, we need to initialize it with this function:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">pmm_init</span><span class="p">(</span><span class="k">struct</span> <span class="n">stivale2_struct</span> <span class="o">*</span><span class="n">stivale2_struct</span><span class="p">);</span>
</code></pre></div></div>
<p>It basically does everything we’ve talked about so far, i.e. setting up the memory map and the bitmap.</p>
<p>To allocate contiguous pages, we can either use this:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">pmm_alloc</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">page_count</span><span class="p">);</span>
</code></pre></div></div>
<p>or preferably this:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">pmm_allocz</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">page_count</span><span class="p">);</span>
</code></pre></div></div>
<p>Which does the same thing as <code class="language-plaintext highlighter-rouge">pmm_alloc</code> except it also memsets the memory returned to zero (-> “clean memory” -> should be preferred).</p>
<p>Allocating consists of finding a free bit in the bitmap, setting it to used and returning the corresponding memory.</p>
<p>To free contiguous pages, the following is used:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">pmm_free</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">pointer</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">page_count</span><span class="p">);</span>
</code></pre></div></div>
<p>Freeing consists of setting the bit corresponding to the pointer passed as an argument to free again, so that the memory can be used again.</p>
<h3 id="slab-allocator">Slab allocator</h3>
<p>The bitmap based page frame allocator is great for page-sized allocations, but when it comes to fine-grained allocations, there would be too much memory wastage. That’s why I’ve implemented a slab allocator, inspired by the design proposed by <a href="https://people.eecs.berkeley.edu/~kubitron/courses/cs194-24-S14/hand-outs/bonwick_slab.pdf">Jeff Bonwick</a>. The basic concept lays in object caching, i.e. storing preallocated objects in a customly defined cache. When allocating, no real memory has to be allocated, only the address of the preallocated object has to be returned. Same goes for freeing: No real memory is freed, only the object is marked as free again.</p>
<p>A cache consists of a linked list of so called slabs. If one slab happens to be fully allocated, a new slab will automatically be created if specified by the user. That’s why in theory, when allocating with the slab allocator, one can’t run out of memory.</p>
<p>A slab itself consists of a freelist or in other words a linked list of control buffers (bufctl).</p>
<p>There are some restrictions though, as the maximum size for a cached object is 512 bytes (so called small slabs). If you want to know more about this issue, please consult the paper by Jeff Bonwick. <code class="language-plaintext highlighter-rouge">malloc</code> solves this problem as we’ll see later.</p>
<p>Now let’s learn how to use the slab allocator:</p>
<p>First, we are going to use slab_cache_create to create a cache for a specific task, in this example inodes for a filesystem.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">slab_cache_t</span> <span class="o">*</span><span class="nf">slab_cache_create</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">slab_size</span><span class="p">,</span> <span class="n">slab_flags_t</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div></div>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// create a cache where each slab is 64 bytes in size, the cache has a description for </span>
<span class="c1">// debugging: "filesystem inodes" and flags to panic if any problem occurs</span>
<span class="n">slab_cache_t</span> <span class="o">*</span><span class="n">filesystem_inode_cache</span> <span class="o">=</span> <span class="n">slab_cache_create</span><span class="p">(</span><span class="s">"filesystem inodes"</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="n">SLAB_PANIC</span><span class="p">);</span>
</code></pre></div></div>
<p>Now to allocate an object of size 64 from the newly created cache, we will use the follwing function:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">slab_cache_alloc</span><span class="p">(</span><span class="n">slab_cache_t</span> <span class="o">*</span><span class="n">cache</span><span class="p">,</span> <span class="n">slab_flags_t</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div></div>
<p>It might look something like this:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// create a cache where each slab is 64 bytes in size, the cache has a description for </span>
<span class="c1">// debugging: "filesystem inodes" and flags to panic if any problem occurs</span>
<span class="n">slab_cache_t</span> <span class="o">*</span><span class="n">filesystem_inode_cache</span> <span class="o">=</span> <span class="n">slab_cache_create</span><span class="p">(</span><span class="s">"filesystem inodes"</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="n">SLAB_PANIC</span><span class="p">);</span>
<span class="c1">// allocate an object from the cache, set flags to panic if any problem occurs</span>
<span class="c1">// and automatically grow the cache if it runs out of slabs</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">inode_ptr_1</span> <span class="o">=</span> <span class="n">slab_cache_alloc</span><span class="p">(</span><span class="n">filesystem_inode_cache</span><span class="p">,</span> <span class="n">SLAB_PANIC</span> <span class="o">|</span> <span class="n">SLAB_AUTO_GROW</span><span class="p">);</span>
</code></pre></div></div>
<p><em>NOTE: We can also manually grow or reap the cache, by using the corresponding functions:</em></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">slab_cache_grow</span><span class="p">(</span><span class="n">slab_cache_t</span> <span class="o">*</span><span class="n">cache</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">count</span><span class="p">,</span> <span class="n">slab_flags_t</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div></div>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">slab_cache_reap</span><span class="p">(</span><span class="n">slab_cache_t</span> <span class="o">*</span><span class="n">cache</span><span class="p">,</span> <span class="n">slab_flags_t</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div></div>
<p>To free our freshly allocated object, we will use the following function:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">slab_cache_free</span><span class="p">(</span><span class="n">slab_cache_t</span> <span class="o">*</span><span class="n">cache</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">pointer</span><span class="p">,</span> <span class="n">slab_flags_t</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div></div>
<p>Our final code might look something like this - I’ve also added a pretty neat debugging tool, to dump the cache:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">slab_cache_dump</span><span class="p">(</span><span class="n">slab_cache_t</span> <span class="o">*</span><span class="n">cache</span><span class="p">,</span> <span class="n">slab_flags_t</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div></div>
<p>-></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// create a cache where each slab is 64 bytes in size, the cache has a description for </span>
<span class="c1">// debugging: "filesystem inodes" and flags to panic if any problem occurs</span>
<span class="n">slab_cache_t</span> <span class="o">*</span><span class="n">filesystem_inode_cache</span> <span class="o">=</span> <span class="n">slab_cache_create</span><span class="p">(</span><span class="s">"filesystem inodes"</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="n">SLAB_PANIC</span><span class="p">);</span>
<span class="c1">// allocate an object from the cache, set flags to panic if any problem occurs</span>
<span class="c1">// and automatically grow the cache if it runs out of slabs</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">inode_ptr_1</span> <span class="o">=</span> <span class="n">slab_cache_alloc</span><span class="p">(</span><span class="n">filesystem_inode_cache</span><span class="p">,</span> <span class="n">SLAB_PANIC</span> <span class="o">|</span> <span class="n">SLAB_AUTO_GROW</span><span class="p">);</span>
<span class="c1">// let's check how our cache looks like at the moment</span>
<span class="n">slab_cache_dump</span><span class="p">(</span><span class="n">filesystem_inode_cache</span><span class="p">,</span> <span class="n">SLAB_PANIC</span><span class="p">);</span>
<span class="c1">// do something nice with inode_ptr_1 :D</span>
<span class="c1">// we don't need our object anymore, so let's free it</span>
<span class="n">slab_cache_free</span><span class="p">(</span><span class="n">filesystem_inode_cache</span><span class="p">,</span> <span class="n">inode_ptr_1</span><span class="p">,</span> <span class="n">SLAB_PANIC</span><span class="p">);</span>
</code></pre></div></div>
<p>And that’s how easy it is to use the slab allocator in apoptOS!</p>
<h2 id="virtual-memory-management">Virtual memory management</h2>
<p>The basic idea of virtual memory is to have a bigger address space, ranging (in our case) from 0x0 to 0xFFFFFFFFFFFFFFFF. To get from virtual memory to physical memory, we use a mapping system. On x86_64 we are provided with paging. In apoptOS, to be specific, we make use of 4-level paging. I won’t go into the details of how paging works, but instead how to use the interface.</p>
<p>To initialize paging and map all memory regions, we’ll use:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vmm_init</span><span class="p">(</span><span class="k">struct</span> <span class="n">stivale2_struct</span> <span class="o">*</span><span class="n">stivale2_struct</span><span class="p">);</span>
</code></pre></div></div>
<p>The resulting virtual memory layout looks like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>First 4 GiB identical:
0x0 - 0x100000000 mapped to 0x0 - 0x100000000
First 4 GiB for higher half data:
0xFFFF800000000000 - 0xFFFF800100000000 mapped to 0x0 - 0x100000000
First 4 GiB for heap:
0xFFFF900000000000 - 0xFFFF900100000000 mapped to 0x0 - 0x100000000
First 2 GiB for higher half code:
0xFFFFFFFF80000000 - 0x0001000000000000 mapped to 0x0 - 0x80000000
All memory map entries:
At higher half data start to all entries in memory map
</code></pre></div></div>
<p>To just map a page, we can use:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vmm_map_page</span><span class="p">(</span><span class="kt">uint64_t</span> <span class="o">*</span><span class="n">page_table</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">phys_page</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">virt_page</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div></div>
<p>And to unmap a page:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vmm_unmap_page</span><span class="p">(</span><span class="kt">uint64_t</span> <span class="o">*</span><span class="n">page_table</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">virt_page</span><span class="p">);</span>
</code></pre></div></div>
<p>We can also map a whole range using:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vmm_map_range</span><span class="p">(</span><span class="kt">uint64_t</span> <span class="o">*</span><span class="n">page_table</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">start</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">end</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">offset</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">flags</span><span class="p">);</span>
</code></pre></div></div>
<p>And to unmap a whole range:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vmm_unmap_range</span><span class="p">(</span><span class="kt">uint64_t</span> <span class="o">*</span><span class="n">page_table</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">start</span><span class="p">,</span> <span class="kt">uint64_t</span> <span class="n">end</span><span class="p">);</span>
</code></pre></div></div>
<p>Whenever we need to map something outside of <code class="language-plaintext highlighter-rouge">src/kernel/memory/virtual/vmm.c</code>, we’ll need to know the address of the root page table. To get it, we have to use:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint64_t</span> <span class="o">*</span><span class="nf">vmm_get_root_page_table</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre></div></div>
<h2 id="heap-memory">Heap memory</h2>
<p>Sometimes we don’t want to allocate a whole page with <code class="language-plaintext highlighter-rouge">pmm_alloc</code> or create a slab cache and allocate from it via <code class="language-plaintext highlighter-rouge">slab_cache_alloc</code>. That might be because we don’t want to waste one whole page for a small allocation, so we’d have to use the slab allocator, but then the sizes might change, so we’d have to create a lot of caches. To fix this issue, apoptOS provides a generic interface, where we don’t have to initialize anything before an allocation. The size we want to allocate can also be anything arbitrary.</p>
<p>TL;DR apoptOS provides a heap interface through <code class="language-plaintext highlighter-rouge">malloc</code> and <code class="language-plaintext highlighter-rouge">free</code>.</p>
<p>In <code class="language-plaintext highlighter-rouge">src/kernel/kernel.c</code> - <code class="language-plaintext highlighter-rouge">kinit_all</code> the following is already called, so this function will never have to be used again:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">malloc_heap_init</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre></div></div>
<p>Allocations and frees from now on are as easy as:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">malloc</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size</span><span class="p">);</span>
</code></pre></div></div>
<p>and</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">free</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">pointer</span><span class="p">);</span>
</code></pre></div></div>
<p>Addresses returned by malloc are always from the heap memory region at 0xFFFF900000000000 (see memory layout in “Virtual memory management”).</p>
<h3 id="detailed-implementation">Detailed implementation</h3>
<p>Last but not least, I’d like to show how I’ve implemented the heap in more detail, as I’ve come up with a quite unique concept. I haven’t done any benchmarks on it yet, but at the moment this allocator will suffice time and efficiency wise. The slab allocator might also be changed in the future to also use large slabs, so this design won’t be needed anymore. Simplicity-wise I can only recommend it!</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">malloc</code> is a mix between the bitmap based page frame allocator and the slab allocator. Former of which is used for allocations above 512 bytes, latter of which is used for allocations below 512 bytes.</li>
<li><code class="language-plaintext highlighter-rouge">malloc_heap_init</code> will create 8 caches, with sizes being power of two, starting with 4 and ending with 512. apoptOS uses 4 as the smallest possible size, as there will always be metadata, which is 2 bytes already.</li>
<li>
<p><code class="language-plaintext highlighter-rouge">malloc</code> will check if the requested size is below or above 512 (to use the appropriate allocator).</p>
<p>-> size <= 512:</p>
<ul>
<li>Update size by adding the size of the metadata struct</li>
<li>Convert updated size to index that’ll be used to access the array of slab caches (e.g., size=5 -> index=1 (corresponding to slab size 8))</li>
</ul>
<p><em>NOTE: This conversion is done by:</em></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">size_t</span> <span class="nf">get_slab_cache_index</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">size</span><span class="p">);</span>
</code></pre></div> </div>
<p><em>Which is a very efficient algorithm (three conditions only), compromising looks of the code. See repo for details.</em></p>
<ul>
<li>Allocate memory with slab allocator (argument=index)</li>
<li>Put metadata struct at beginning of allocated memory - Metadata contains slab caches index</li>
</ul>
<p>-> size > 512</p>
<ul>
<li>Update size by adding the size of the metadata struct and page aligning it</li>
<li>Convert udpated size to page count</li>
<li>Allocate memory with bitmap based page frame allocator (argument=page count)</li>
<li>Put metadata struct at beginning of allocated memory - Metadata contains page count</li>
</ul>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">free</code> will check if the pointer ends with 0xFFF bits by bitwise ANDing</p>
<p>-> not true</p>
<ul>
<li>Get slab caches index from metadata at pointer passed as argument</li>
<li>Free memory with slab allocator (argument=index)</li>
</ul>
<p>-> true</p>
<ul>
<li>Get page count from metadata at pointer passed as argument</li>
<li>Free memory with bitmap based page frame allocator (argument=page count)</li>
</ul>
</li>
</ol>
<p>And that’s the whole deal with memory. Of course, everything is very basic, but for now it wouldn’t make sense to implement more, instead let’s start adding more features to apoptOS!</p>
<h2 id="next">Next</h2>
<p><a href="https://tix3dev.github.io/apoptos-series-2">-</a></p>
<h2 id="references">References</h2>
<ul>
<li>https://github.com/Tix3Dev/apoptOS/blob/9a4fde1fe18abb4fb91d89a29ae21bde7c0cbea5/src/kernel/memory/physical/pmm.c</li>
<li>https://github.com/Tix3Dev/apoptOS/blob/9a4fde1fe18abb4fb91d89a29ae21bde7c0cbea5/src/kernel/memory/virtual/vmm.c</li>
<li>https://github.com/Tix3Dev/apoptOS/blob/9a4fde1fe18abb4fb91d89a29ae21bde7c0cbea5/src/kernel/memory/dynamic/slab.c</li>
<li>https://github.com/Tix3Dev/apoptOS/blob/9a4fde1fe18abb4fb91d89a29ae21bde7c0cbea5/src/kernel/libk/malloc/malloc.c</li>
<li>https://github.com/limine-bootloader/limine</li>
<li>https://github.com/stivale/stivale</li>
<li>https://people.eecs.berkeley.edu/~kubitron/courses/cs194-24-S14/hand-outs/bonwick_slab.pdf</li>
</ul>Yves VollmeierForeword In this blog post I will talk about the concepts for memory management in apoptOS and how to use them.Using OSDev-related documentation2022-02-17T00:00:00+00:002022-02-17T00:00:00+00:00https://tix3dev.github.io//using-osdev-related-documentation<h2 id="foreword">Foreword</h2>
<p>It can be a quite daunting task for newcomers to the OSDev world to read documentation like the Intel System Programming Guide or UEFI specifications.
Even once the desired part is found in the sheer endless documentation, it’s still hard to make use of those technical information’s.</p>
<p>As I am slowly getting better at extracting such information’s, I wanted to share a few tips and tricks using an example.</p>
<h2 id="example-implementing-rsdp-structure-for-acpi">Example: Implementing RSDP structure for ACPI</h2>
<p>In case you don’t know yet, in order to parse ACPI tables like MADT etc., it’s necessary to find the “Root System Description Pointer” (short: RSDP). After that, we need to extract information from it.</p>
<p>So what I did, as hopefully every programmer would do, was to search for this structure (in my case in the UEFI ACPI specification). And fortunately, also found it:</p>
<p><img src="https://raw.githubusercontent.com/Tix3Dev/tix3dev.github.io/main/_posts/2022-02-17-using-osdev-related-documentation-pictures/UEFI_Spec_RSDP_Structure.png" alt="RSDP Structure from UEFI ACPI specification" /></p>
<p>First step done!</p>
<p>Next step is to read all information’s contained in this table. It’s really worth reading it carefully and trying to understand everything (although 100% isn’t necessary, as it’s already very helpful just having heard the terms for the future).
But as always, if you don’t understand a key part, you can just search for it on the internet. E.g., I had to search for OEM and thanks to that, I now know that it stands for “Original equipment manufacturer” and a common example are computer manufacturers that integrate OEM parts such as processors or software into their own product.</p>
<p>That’s cool and all, but we still need to “convert” this table into code, which is our last step.</p>
<p>I started off by writing some pseudocode, which eventually will turn into C code:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span>
<span class="p">{</span>
<span class="c1">// ACPI version 1.0</span>
<span class="n">var</span> <span class="n">signature</span><span class="p">;</span>
<span class="n">var</span> <span class="n">checksum</span><span class="p">;</span>
<span class="n">var</span> <span class="n">oemid</span><span class="p">;</span>
<span class="n">var</span> <span class="n">revision</span><span class="p">;</span>
<span class="n">var</span> <span class="n">rsdt_address</span><span class="p">;</span>
<span class="c1">// ACPI version 2.0+</span>
<span class="n">var</span> <span class="n">length</span><span class="p">;</span>
<span class="n">var</span> <span class="n">xsdt_address</span><span class="p">;</span>
<span class="n">var</span> <span class="n">extended_checksum</span><span class="p">;</span>
<span class="n">var</span> <span class="n">reserved</span><span class="p">;</span>
<span class="p">}</span> <span class="n">rsdp_structure_t</span><span class="p">;</span>
</code></pre></div></div>
<p>(The fact that this is a struct just comes from the ACPI context.)</p>
<p>As you can see, for now I only defined a struct with non-existing data types. Our main goal now is to change them into proper ones.</p>
<p>Let’s start changing the easy ones, whose types are described in the “Description” part:</p>
<p><img src="https://raw.githubusercontent.com/Tix3Dev/tix3dev.github.io/main/_posts/2022-02-17-using-osdev-related-documentation-pictures/Easy_Items.png" alt="Easy_Items" /></p>
<p>-></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span>
<span class="p">{</span>
<span class="c1">// ACPI version 1.0</span>
<span class="n">var</span> <span class="n">signature</span><span class="p">;</span>
<span class="n">var</span> <span class="n">checksum</span><span class="p">;</span>
<span class="n">var</span> <span class="n">oemid</span><span class="p">;</span>
<span class="n">var</span> <span class="n">revision</span><span class="p">;</span>
<span class="kt">uint32_t</span> <span class="n">rsdt_address</span><span class="p">;</span> <span class="c1">// <-</span>
<span class="c1">// ACPI version 2.0+</span>
<span class="n">var</span> <span class="n">length</span><span class="p">;</span>
<span class="kt">uint64_t</span> <span class="n">xsdt_address</span><span class="p">;</span> <span class="c1">// <-</span>
<span class="n">var</span> <span class="n">extended_checksum</span><span class="p">;</span>
<span class="n">var</span> <span class="n">reserved</span><span class="p">;</span>
<span class="p">}</span> <span class="n">rsdp_structure_t</span><span class="p">;</span>
</code></pre></div></div>
<p>As we can see and will see, it’s very important to know how big a data type is.
This should help fresh things up:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Some important C data types for the x86_64 architecture</span>
<span class="kt">char</span> <span class="n">var1</span><span class="p">;</span> <span class="c1">// 1 byte</span>
<span class="kt">short</span> <span class="n">var2</span><span class="p">;</span> <span class="c1">// 2 bytes</span>
<span class="kt">int</span> <span class="n">var3</span><span class="p">;</span> <span class="c1">// 4 bytes</span>
<span class="kt">long</span> <span class="n">var4</span><span class="p">;</span> <span class="c1">// 8 bytes</span>
<span class="c1">// Generally what would be preferred in OSDev</span>
<span class="kt">uint8_t</span> <span class="n">var5</span><span class="p">;</span> <span class="c1">// 8 bits = 1 byte</span>
<span class="kt">uint16_t</span> <span class="n">var6</span><span class="p">;</span> <span class="c1">// 16 bits = 2 bytes</span>
<span class="kt">uint32_t</span> <span class="n">var7</span><span class="p">;</span> <span class="c1">// 32 bits = 4 bytes</span>
<span class="kt">uint64_t</span> <span class="n">var8</span><span class="p">;</span> <span class="c1">// 64 bits = 8 bytes</span>
</code></pre></div></div>
<p>Next up we can tell by the naming that the following ones are a string and we also get the byte length that they take up, which is just the <code class="language-plaintext highlighter-rouge">[n]</code>, as one char is one byte:</p>
<p><img src="https://raw.githubusercontent.com/Tix3Dev/tix3dev.github.io/main/_posts/2022-02-17-using-osdev-related-documentation-pictures/String_Items.png" alt="String_Items" /></p>
<p>-></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span>
<span class="p">{</span>
<span class="c1">// ACPI version 1.0</span>
<span class="kt">char</span> <span class="n">signature</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span> <span class="c1">// <-</span>
<span class="n">var</span> <span class="n">checksum</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">oemid</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span> <span class="c1">// <-</span>
<span class="n">var</span> <span class="n">revision</span><span class="p">;</span>
<span class="kt">uint32_t</span> <span class="n">rsdt_address</span><span class="p">;</span>
<span class="c1">// ACPI version 2.0+</span>
<span class="n">var</span> <span class="n">length</span><span class="p">;</span>
<span class="kt">uint64_t</span> <span class="n">xsdt_address</span><span class="p">;</span>
<span class="n">var</span> <span class="n">extended_checksum</span><span class="p">;</span>
<span class="n">var</span> <span class="n">reserved</span><span class="p">;</span>
<span class="p">}</span> <span class="n">rsdp_structure_t</span><span class="p">;</span>
</code></pre></div></div>
<p>If we have a look at the byte length column, we can see that the following ones have the same length (namely 1 byte = 8 bits):</p>
<p><img src="https://raw.githubusercontent.com/Tix3Dev/tix3dev.github.io/main/_posts/2022-02-17-using-osdev-related-documentation-pictures/One_Byte_Length_Items.png" alt="One_Byte_Length_Items" /></p>
<p>-></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span>
<span class="p">{</span>
<span class="c1">// ACPI version 1.0</span>
<span class="kt">char</span> <span class="n">signature</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span>
<span class="kt">uint8_t</span> <span class="n">checksum</span><span class="p">;</span> <span class="c1">// <-</span>
<span class="kt">char</span> <span class="n">oemid</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span>
<span class="kt">uint8_t</span> <span class="n">revision</span><span class="p">;</span> <span class="c1">// <-</span>
<span class="kt">uint32_t</span> <span class="n">rsdt_address</span><span class="p">;</span>
<span class="c1">// ACPI version 2.0+</span>
<span class="n">var</span> <span class="n">length</span><span class="p">;</span>
<span class="kt">uint64_t</span> <span class="n">xsdt_address</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="n">extended_checksum</span><span class="p">;</span> <span class="c1">// <-</span>
<span class="n">var</span> <span class="n">reserved</span><span class="p">;</span>
<span class="p">}</span> <span class="n">rsdp_structure_t</span><span class="p">;</span>
</code></pre></div></div>
<p>The table in the documentation says, that the field “Length”, has a byte length of 4 bytes = 32 bits</p>
<p><img src="https://raw.githubusercontent.com/Tix3Dev/tix3dev.github.io/main/_posts/2022-02-17-using-osdev-related-documentation-pictures/Length_Item.png" alt="Length_Item" /></p>
<p>-></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span>
<span class="p">{</span>
<span class="c1">// ACPI version 1.0</span>
<span class="kt">char</span> <span class="n">signature</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span>
<span class="kt">uint8_t</span> <span class="n">checksum</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">oemid</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span>
<span class="kt">uint8_t</span> <span class="n">revision</span><span class="p">;</span>
<span class="kt">uint32_t</span> <span class="n">rsdt_address</span><span class="p">;</span>
<span class="c1">// ACPI version 2.0+</span>
<span class="kt">uint32_t</span> <span class="n">length</span><span class="p">;</span> <span class="c1">// <-</span>
<span class="kt">uint64_t</span> <span class="n">xsdt_address</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="n">extended_checksum</span><span class="p">;</span>
<span class="n">var</span> <span class="n">reserved</span><span class="p">;</span>
<span class="p">}</span> <span class="n">rsdp_structure_t</span><span class="p">;</span>
</code></pre></div></div>
<p>Finally, we’ve got the field “Reserved”, which has a byte length of 3. Oh no, what now? We don’t have a data type with that size… Actually, that’s an easy fix, let’s just use 3 uint8_t -> 3 * 1 byte = 3 bytes.</p>
<p><img src="https://raw.githubusercontent.com/Tix3Dev/tix3dev.github.io/main/_posts/2022-02-17-using-osdev-related-documentation-pictures/Reserved_Item.png" alt="Reserved" /></p>
<p>-></p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span>
<span class="p">{</span>
<span class="c1">// ACPI version 1.0</span>
<span class="kt">char</span> <span class="n">signature</span><span class="p">[</span><span class="mi">8</span><span class="p">];</span>
<span class="kt">uint8_t</span> <span class="n">checksum</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">oemid</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span>
<span class="kt">uint8_t</span> <span class="n">revision</span><span class="p">;</span>
<span class="kt">uint32_t</span> <span class="n">rsdt_address</span><span class="p">;</span>
<span class="c1">// ACPI version 2.0+</span>
<span class="kt">uint32_t</span> <span class="n">length</span><span class="p">;</span>
<span class="kt">uint64_t</span> <span class="n">xsdt_address</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="n">extended_checksum</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="n">reserved</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
<span class="p">}</span> <span class="n">rsdp_structure_t</span><span class="p">;</span>
</code></pre></div></div>
<p>And that’s it, our final struct, ready to use for ACPI table parsing!</p>
<h2 id="references">References</h2>
<ul>
<li>https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf</li>
</ul>Yves VollmeierForewordMarkdown Syntax Preview2021-10-21T00:00:00+00:002021-10-21T00:00:00+00:00https://tix3dev.github.io//markdown-syntax-preview<h2 id="philosophy">Philosophy:</h2>
<p><mark>Markdown</mark> is intended to be as easy-to-read and easy-to-write as is feasible.</p>
<p>Readability, however, is emphasized above all else. A Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions. While Markdown’s syntax has been influenced by several existing text-to-HTML filters — including Setext, atx, Textile, reStructuredText, Grutatext, and EtText — the single biggest source of inspiration for Markdown’s syntax is the format of plain text email.</p>
<p>To this end, Markdown’s syntax is comprised entirely of punctuation characters, which punctuation characters have been carefully chosen so as to look like what they mean. E.g., asterisks around a word actually look like <em>emphasis</em>. Markdown lists look like, well, lists. Even blockquotes look like quoted passages of text, assuming you’ve ever used email.
Inline HTML</p>
<blockquote>
<p>Markdown’s syntax is intended for one purpose: to be used as a format for writing for the web.</p>
</blockquote>
<p>Markdown is not a replacement for HTML, or even close to it. Its syntax is very small, corresponding only to a very small subset of HTML tags. The idea is not to create a syntax that makes it easier to insert HTML tags. In my opinion, HTML tags are already easy to insert. The idea for Markdown is to make it easy to read, write, and edit prose. HTML is a publishing format; Markdown is a writing format. Thus, Markdown’s formatting syntax only addresses issues that can be conveyed in plain text.</p>
<p>For any markup that is not covered by Markdown’s syntax, you simply use HTML itself. There’s no need to preface it or delimit it to indicate that you’re switching from Markdown to HTML; you just use the tags.</p>
<p>The only restrictions are that block-level HTML elements — e.g. <code class="language-plaintext highlighter-rouge"><div></code>, <code class="language-plaintext highlighter-rouge"><table></code>, <code class="language-plaintext highlighter-rouge"><pre></code>, <code class="language-plaintext highlighter-rouge"><p></code>, etc. — must be separated from surrounding content by blank lines, and the start and end tags of the block should not be indented with tabs or spaces. Markdown is smart enough not to add extra (unwanted) <code class="language-plaintext highlighter-rouge"><p></code> tags around HTML block-level tags. <a href="https://daringfireball.net/projects/markdown/syntax"><strong>Source</strong></a></p>
<h2 id="basic-markdown-formatting">Basic Markdown Formatting</h2>
<h3 id="headings">Headings</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># This is an <h1> tag
## This is an <h2> tag
### This is an <h3> tag
#### This is an <h4> tag
##### This is an <h5> tag
###### This is an <h6> tag
</code></pre></div></div>
<h3 id="emphasis">Emphasis</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
_You **can** combine them_
</code></pre></div></div>
<p>Result:</p>
<p><em>This text will be italic</em></p>
<p><em>This will also be italic</em></p>
<p><strong>This text will be bold</strong></p>
<p><strong>This will also be bold</strong></p>
<p><em>You <strong>can</strong> combine them</em></p>
<h3 id="lists">Lists</h3>
<p><strong>Inordered:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>* Milk
* Bread
* Wholegrain
* Butter
</code></pre></div></div>
<p>Result:</p>
<ul>
<li>Milk</li>
<li>Bread
<ul>
<li>Wholegrain</li>
</ul>
</li>
<li>Butter</li>
</ul>
<p><strong>Ordered:</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1. Tidy the kitchen
2. Prepare ingredients
3. Cook delicious things
</code></pre></div></div>
<p>Result:</p>
<ol>
<li>Tidy the kitchen</li>
<li>Prepare ingredients</li>
<li>Cook delicious things</li>
</ol>
<h3 id="images">Images</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
</code></pre></div></div>
<p>Result:</p>
<p><img src="http://i.imgur.com/v8IVDka.jpg" alt="m'lady" /></p>
<h3 id="links">Links</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[link](http://example.com)
</code></pre></div></div>
<p>Result:</p>
<p><a href="http://example.com">link</a></p>
<h3 id="blockquotes">Blockquotes</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>As Kanye West said:
> We're living the future so
> the present is our past.
</code></pre></div></div>
<p>Result:</p>
<p>As Kanye West said:</p>
<blockquote>
<p>We’re living the future so
the present is our past.</p>
</blockquote>
<h3 id="horizontal-rules">Horizontal Rules</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>---
</code></pre></div></div>
<p>Result:</p>
<hr />
<h3 id="code-snippets">Code Snippets</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Indenting by 4 spaces will turn an entire paragraph into a code-block.
</code></pre></div></div>
<p>Result:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.my-link {
text-decoration: underline;
}
</code></pre></div></div>
<h3 id="reference-lists--titles">Reference Lists & Titles</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>**The quick brown [fox][1], jumped over the lazy [dog][2].**
[1]: https://en.wikipedia.org/wiki/Fox "Wikipedia: Fox"
[2]: https://en.wikipedia.org/wiki/Dog "Wikipedia: Dog"
</code></pre></div></div>
<p>Result:</p>
<p><strong>The quick brown <a href="https://en.wikipedia.org/wiki/Fox" title="Wikipedia: Fox">fox</a>, jumped over the lazy <a href="https://en.wikipedia.org/wiki/Dog" title="Wikipedia: Dog">dog</a>.</strong></p>
<h3 id="escaping">Escaping</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>\*literally\*
</code></pre></div></div>
<p>Result:</p>
<p>*literally*</p>
<h3 id="embedding-html">Embedding HTML</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><button class="button-save large">Big Fat Button</button>
</code></pre></div></div>
<p>Result:</p>
<p><button class="button-save large">Big Fat Button</button></p>
<h2 id="advanced-markdown">Advanced Markdown</h2>
<p>Note: Some syntax which is not standard to native Markdown. They’re extensions of the language.</p>
<h3 id="strike-throughs">Strike-throughs</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~~deleted words~~
</code></pre></div></div>
<p>Result:</p>
<p><del>deleted words</del></p>
<h3 id="automatic-links">Automatic Links</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://ghost.org
</code></pre></div></div>
<p>Result:</p>
<p>https://ghost.org</p>
<h3 id="markdown-footnotes">Markdown Footnotes</h3>
<p>Work in <a href="https://ghost.org/">Ghost</a>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The quick brown fox[^1] jumped over the lazy dog[^2].
[^1]: Foxes are red
[^2]: Dogs are usually not red
</code></pre></div></div>
<p>Result:</p>
<p>The quick brown fox<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> jumped over the lazy dog<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>
<h2 id="github-flavored-markdown">GitHub Flavored Markdown</h2>
<h3 id="syntax-highlighting">Syntax Highlighting</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>```javascript
function fancyAlert(arg) {
if(arg) {
$.facebox({div:'#foo'})
}
}
```
</code></pre></div></div>
<p>Result:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">fancyAlert</span><span class="p">(</span><span class="nx">arg</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">arg</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">.</span><span class="nx">facebox</span><span class="p">({</span> <span class="na">div</span><span class="p">:</span> <span class="dl">"</span><span class="s2">#foo</span><span class="dl">"</span> <span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="task-lists">Task Lists</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- [x] @mentions, #refs, [links](), **formatting**, and <del>tags</del> supported
- [x] list syntax required (any unordered or ordered list supported)
- [x] this is a complete item
- [ ] this is an incomplete item
</code></pre></div></div>
<p>Result:</p>
<ul class="task-list">
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" checked="checked" />@mentions, #refs, <a href="">links</a>, <strong>formatting</strong>, and <del>tags</del> supported</li>
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" checked="checked" />list syntax required (any unordered or ordered list supported)</li>
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" checked="checked" />this is a complete item</li>
<li class="task-list-item"><input type="checkbox" class="task-list-item-checkbox" disabled="disabled" />this is an incomplete item</li>
</ul>
<h3 id="tables">Tables</h3>
<p>You can create tables by assembling a list of words and dividing them with hyphens <code class="language-plaintext highlighter-rouge">-</code> (for the first row), and then separating each column with a pipe <code class="language-plaintext highlighter-rouge">|</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>First Header | Second Header | Third Header |
------------ | ------------- ----------------
Content from cell 1 | Content from cell 2 | Content from cell 3 |
Content in the first column | Content in the second column | Content in the third column |
Content in the forth row A | Content in the forth row B | Content in the forth row C |
</code></pre></div></div>
<table>
<thead>
<tr>
<th>First Header</th>
<th>Second Header</th>
<th>Third Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Content from cell 1</td>
<td>Content from cell 2</td>
<td>Content from cell 3</td>
</tr>
<tr>
<td>Content in the first column</td>
<td>Content in the second column</td>
<td>Content in the third column</td>
</tr>
<tr>
<td>Content in the forth row A</td>
<td>Content in the forth row B</td>
<td>Content in the forth row C</td>
</tr>
</tbody>
</table>
<h2 id="references">References</h2>
<ul>
<li>http://blog.ghost.org/markdown/</li>
<li>https://guides.github.com/features/mastering-markdown/</li>
</ul>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>Foxes are red <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>Dogs are usually not red <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>Yves VollmeierPhilosophy: