1import{_ as s,c as a,e,o as i}from"./app-CjUkjRdW.js";const l="/assets/boot-loadedimage-CgOQRvkZ.png",o="/assets/boot-simplefilesystem-CXb1hauC.png",p="/assets/boot-openkernelfile-BCIAOz9r.png",t="/assets/boot-kernelfilesize-LMZUay_C.png",c={};function r(d,n){return i(),a("div",null,n[0]||(n[0]=[e(`<h1 id="loading-the-kernel-part-1" tabindex="-1"><a class="header-anchor" href="#loading-the-kernel-part-1"><span>Loading the Kernel (Part 1)</span></a></h1><p>In the last section we built a raw binary kernel image. We'll pick up where we left off in the bootloader and load the kernel image into memory. We'll rely on UEFI Boot Services to do so.</p><h2 id="uefi-boot-services" tabindex="-1"><a class="header-anchor" href="#uefi-boot-services"><span>UEFI Boot Services</span></a></h2><p>UEFI Boot Services provides a number of services to help us, including accessing the file system, getting information about a file, allocating memory, and reading a file into memory. Here's the plan:</p><ul><li>Use the bootloader image <code>EfiHandle</code> (which is passed to the entry point) to get its <code>EfiLoadedImageProtocol</code>.</li><li>Use the <code>EfiLoadedImageProtocol</code> device handle to get the <code>EfiSimpleFileSystemProtocol</code> of that device.</li><li>Use the <code>EfiSimpleFileSystemProtocol</code> to get the <code>EfiFileSystemInfo</code> representing the root directory of the file system.</li><li>Use the <code>EfiSimpleFileSystemProtocol</code> and the kernel image path on the file system to get the <code>EfiFileProtocol</code> of the kernel file.</li><li>Use the <code>EfiFileProtocol</code> to get the <code>EfiFileInfo</code> of the kernel file, which contains the size of the file.</li><li>Use the Boot Services <code>AllocatePages</code> function to allocate enough pages, starting at address <code>0x100000</code> (1 MiB), to hold the kernel image.</li><li>Use <code>AllocatePages</code> to allocate a region for the kernel stack.</li><li>Use the <code>EfiFileProtocol</code> function to read the kernel image into memory.</li></ul><p>After reading the kernel into memory, and before jumping to it, we'll need to call the Boot Services <code>ExitBootServices</code> function to signal to the UEFI firmware that we're done with the Boot Services. To do so, we're required to also call the <code>GetMemoryMap</code> function to get the memory map, which contains a key that we'll pass to <code>ExitBootServices</code>. We'll also eventually pass this memory map to the kernel. So in addition to the plan above, we'll also:</p><ul><li>Use the Boot Services <code>GetMemoryMap</code> function to get the memory map.</li><li>Use the Boot Services <code>ExitBootServices</code> function, passing it the memory map key.</li><li>Jump to the kernel image starting address.</li></ul><p>This is a lot to take in, but this is how the UEFI spec was designed ¯\\<em>(ã)</em>/¯. We'll take it one step at a time.</p><h2 id="boot-device-handle" tabindex="-1"><a class="header-anchor" href="#boot-device-handle"><span>Boot device handle</span></a></h2><p>Since we plan on storing the kernel image on the same device as the bootloader, we want to access the file system of the device from which the bootloader was loaded. The <code>EfiLoadedImageProtocol</code> (which we can get through the bootloader image handle) has a <code>DeviceHandle</code> field that we can use to get the <code>EfiSimpleFileSystemProtocol</code> of that device. So let's define the <code>EfiLoadedImageProtocol</code> in <code>src/common/uefi.nim</code>.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/common/uefi.nim</span></span> 2<span class="line"></span> 3<span class="line"><span class="token keyword">type</span></span> 4<span class="line"> <span class="token operator">...</span></span> 5<span class="line"> EfiLoadedImageProtocol<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 6<span class="line"> revision<span class="token operator">*:</span> uint32</span> 7<span class="line"> parentHandle<span class="token operator">*:</span> EfiHandle</span> 8<span class="line">
8 systemTable<span class="token operator">*:</span> <span class="token keyword">ptr</span> EfiSystemTable</span> 9<span class="line"> <span class="token comment"># Source location of the image</span></span> 10<span class="line highlighted"> deviceHandle<span class="token operator">*:</span> EfiHandle</span> 11<span class="line"> filePath<span class="token operator">*:</span> pointer</span> 12<span class="line"> reserved<span class="token operator">*:</span> pointer</span> 13<span class="line"> <span class="token comment"># Image's load options</span></span> 14<span class="line"> loadOptionsSize<span class="token operator">*:</span> uint32</span> 15<span class="line"> loadOptions<span class="token operator">*:</span> pointer</span> 16<span class="line"> <span class="token comment"># Location where image was loaded</span></span> 17<span class="line"> imageBase<span class="token operator">*:</span> pointer</span> 18<span class="line"> imageSize<span class="token operator">*:</span> uint64</span> 19<span class="line"> imageCodeType<span class="token operator">*:</span> EfiMemoryType</span> 20<span class="line"> imageDataType<span class="token operator">*:</span> EfiMemoryType</span> 21<span class="line"> unload<span class="token operator">*:</span> pointer</span> 22<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>The <code>EfiMemoryType</code> defines the various types of memory in the system. At some point, we'll need to allocate memory for the kernel (code, data, and stack), so we'll need to differentiate between these types of memory. The UEFI spec doesn't define kernel memory types, so we'll add a few more custom types to the enum, which fall in the range of OSV (Operating System Vendor) defined memory types (<code>0x80000000</code> to <code>0xFFFFFFFF</code>).</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"> EfiMemoryType<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">enum</span></span> 23<span class="line"> EfiReservedMemory</span> 24<span class="line"> EfiLoaderCode</span> 25<span class="line"> EfiLoaderData</span> 26<span class="line"> EfiBootServicesCode</span> 27<span class="line"> EfiBootServicesData</span> 28<span class="line"> EfiRuntimeServicesCode</span> 29<span class="line"> EfiRuntimeServicesData</span> 30<span class="line"> EfiConventionalMemory</span> 31<span class="line"> EfiUnusableMemory</span> 32<span class="line"> EfiACPIReclaimMemory</span> 33<span class="line"> EfiACPIMemoryNVS</span> 34<span class="line"> EfiMemoryMappedIO</span> 35<span class="line"> EfiMemoryMappedIOPortSpace</span> 36<span class="line">
36 EfiPalCode</span> 37<span class="line"> EfiPersistentMemory</span> 38<span class="line"> EfiUnacceptedMemory</span> 39<span class="line"> OsvKernelCode <span class="token operator">=</span> <span class="token number">0x80000000</span></span> 40<span class="line"> OsvKernelData <span class="token operator">=</span> <span class="token number">0x80000001</span></span> 41<span class="line"> OsvKernelStack <span class="token operator">=</span> <span class="token number">0x80000002</span></span> 42<span class="line"> EfiMaxMemoryType</span> 43<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>To get the <code>EfiLoadedImageProtocol</code> from the bootloader image handle, we'll use the <code>handleProtocol</code> function of the Boot Services. So let's define the <code>BootServices</code> type and the <code>handleProtocol</code> function in <code>src/common/uefi.nim</code>. It's a large type with many functions, so I won't define the type of every field; we'll use <code>pointer</code> for those fields until we need to use them.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/common/uefi.nim</span></span> 44<span class="line"></span> 45<span class="line"><span class="token keyword">type</span></span> 46<span class="line"> EfiBootServices<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 47<span class="line"> hdr<span class="token operator">*:</span> EfiTableHeader</span> 48<span class="line"> <span class="token comment"># task priority services</span></span> 49<span class="line"> raiseTpl<span class="token operator">*:</span> pointer</span> 50<span class="line"> restoreTpl<span class="token operator">*:</span> pointer</span> 51<span class="line"> <span class="token comment"># memory services</span></span> 52<span class="line"> allocatePages<span class="token operator">*:</span> pointer</span> 53<span class="line"> freePages<span class="token operator">*:</span> pointer</span> 54<span class="line"> getMemoryMap<span class="token operator">*:</span> pointer</span> 55<span class="line"> allocatePool<span class="token operator">*:</span> pointer</span> 56<span class="line"> freePool<span class="token operator">*:</span> pointer</span> 57<span class="line"> <span class="token comment"># event & timer services</span></span> 58<span class="line"> createEvent<span class="token operator">*:</span> pointer</span> 59<span class="line"> setTimer<span class="token operator">*:</span> pointer</span> 60<span class="line"> waitForEvent<span class="token operator">*:</span> pointer</span> 61<span class="line"> signalEvent<span class="token operator">*:</span> pointer</span> 62<span class="line"> closeEvent<span class="token operator">*:</span> pointer</span> 63<span class="line"> checkEvent<span class="token operator">*:</span> pointer</span> 64<span class="line"> <span class="token comment"># protocol handler services</span></span> 65<span class="line"> installProtocolInterface<span class="token operator">*:</span> pointer</span> 66<span class="line"> reinstallProtocolInterface<span class="token operator">*:</span> pointer</span> 67<span class="line"> uninstallProtocolInterface<span class="token operator">*:</span> pointer</span> 68<span class="line"> handleProtocol<span class="token operator">*:</span> <span class="token function">proc</span> <span class="token punctuation">(</span>handle<span class="token operator">:</span> EfiHandle<span class="token punctuation">,</span> protocol<span class="token operator">:</span> EfiGuid<span class="token punctuation">,</span> <span class="token identifier"><span class="token punctuation">\`</span>interface<span class="token punctuation">\`</span></span><span class="token operator">:</span> <span class="token keyword">ptr</span> pointer<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token punctuation">{.</span>cdecl<span class="token punctuation">.}</span></span> 69<span class="line"> reserved<span class="token operator">*:</span> pointer</span> 70<span class="line"> registerProtocolNotify<span class="token operator">*:</span> pointer</span> 71<span class="line"> locateHandle<span class="token operator">*:</span> pointer</span> 72<span class="line"> locateDevicePath<span class="token operator">*:</span> pointer</span> 73<span class="line"> installConfigurationTable<span class="token operator">*:</span> pointer</span> 74<span class="line"> <span class="token comment"># image services</span></span> 75<span class="line">
75 loadImage<span class="token operator">*:</span> pointer</span> 76<span class="line"> startImage<span class="token operator">*:</span> pointer</span> 77<span class="line"> exit<span class="token operator">*:</span> pointer</span> 78<span class="line"> unloadImage<span class="token operator">*:</span> pointer</span> 79<span class="line"> exitBootServices<span class="token operator">*:</span> pointer</span> 80<span class="line"> <span class="token comment"># misc services</span></span> 81<span class="line"> getNextMonotonicCount<span class="token operator">*:</span> pointer</span> 82<span class="line"> stall<span class="token operator">*:</span> pointer</span> 83<span class="line"> setWatchdogTimer<span class="token operator">*:</span> pointer</span> 84<span class="line"> <span class="token comment"># driver support services</span></span> 85<span class="line"> connectController<span class="token operator">*:</span> pointer</span> 86<span class="line"> disconnectController<span class="token operator">*:</span> pointer</span> 87<span class="line"> <span class="token comment"># open and close protocol services</span></span> 88<span class="line"> openProtocol<span class="token operator">*:</span> pointer</span> 89<span class="line"> closeProtocol<span class="token operator">*:</span> pointer</span> 90<span class="line"> openProtocolInformation<span class="token operator">*:</span> pointer</span> 91<span class="line"> <span class="token comment"># library services</span></span> 92<span class="line"> protocolsPerHandle<span class="token operator">*:</span> pointer</span> 93<span class="line"> locateHandleBuffer<span class="token operator">*:</span> pointer</span> 94<span class="line"> locateProtocol<span class="token operator">*:</span> pointer</span> 95<span class="line"> installMultipleProtocolInterfaces<span class="token operator">*:</span> pointer</span> 96<span class="line"> uninstallMultipleProtocolInterfaces<span class="token operator">*:</span> pointer</span> 97<span class="line"> <span class="token comment"># 32-bit CRC services</span></span> 98<span class="line"> calculateCrc32<span class="token operator">*:</span> pointer</span> 99<span class="line"> <span class="token comment"># misc services</span></span> 100<span class="line"> copyMem<span class="token operator">*:</span> pointer</span> 101<span class="line"> setMem<span class="token operator">*:</span> pointer</span> 102<span class="line"> createEventEx<span class="token operator">*:</span> pointer</span> 103<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>One of the parameters of the <code>handleProtocol</code> function is of type <code>EfiGuid</code>. Let's define it as well.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token keyword">type</span></span> 104<span class="line"> EfiGuid<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 105<span class="line"> data1<span class="token operator">:</span> uint32</span> 106<span class="line"> data2<span class="token operator">:</span> uint16</span> 107<span class="line"> data3<span class="token operator">:</span> uint16</span> 108<span class="line"> data4<span class="token operator">:</span> array<span class="token punctuation">[</span><span class="token number">8</span><span class="token punctuation">,</span> uint8<span class="token punctuation">]</span></span> 109<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>We're interested in the <code>EfiLoadedImageProtocol</code>, so we need to define its GUID.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token keyword">const</span></span> 110<span class="line"> EfiLoadedImageProtocolGuid<span class="token operator">*</span> <span class="token operator">=</span> <span class="token function">EfiGuid</span><span class="token punctuation">(</span></span> 111<span class="line"> data1<span class="token operator">:</span> <span class="token number">0x5B1B31A1</span><span class="token punctuation">,</span> data2<span class="token operator">:</span> <span class="token number">0x9562</span><span class="token punctuation">,</span> data3<span class="token operator">:</span> <span class="token number">0x11d2</span><span class="token punctuation">,</span></span> 112<span class="line"> data4<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0x8e</span><span class="token punctuation">,</span> <span class="token number">0x3f</span><span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">0xa0</span><span class="token punctuation">,</span> <span class="token number">0xc9</span><span class="token punctuation">,</span> <span class="token number">0x69</span><span class="token punctuation">,</span> <span class="token number">0x72</span><span class="token punctuation">,</span> <span class="token number">0x3b</span><span class="token punctuation">]</span></span> 113<span class="line"> <span class="token punctuation">)</span></span> 114<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Now we're ready to call the <code>handleProtocol</code> function to get the <code>EfiLoadedImageProtocol</code> from the bootloader image handle.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/boot/bootx64.nim</span></span> 115<span class="line"></span> 116<span class="line highlighted"><span class="token keyword">
116import</span> common<span class="token operator">/</span>uefi</span> 117<span class="line"><span class="token operator">...</span></span> 118<span class="line"></span> 119<span class="line highlighted"><span class="token keyword">proc</span> <span class="token function">checkStatus<span class="token operator">*</span></span><span class="token punctuation">(</span>status<span class="token operator">:</span> EfiStatus<span class="token punctuation">)</span> <span class="token operator">=</span></span> 120<span class="line highlighted"> <span class="token keyword">if</span> status <span class="token operator">!=</span> EfiSuccess<span class="token operator">:</span></span> 121<span class="line highlighted"> consoleOut <span class="token operator">&</span><span class="token string">" [failed, status = {status:#x}]"</span></span> 122<span class="line highlighted"> <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 123<span class="line highlighted"> consoleOut <span class="token string">" [success]\\r\\n"</span></span> 124<span class="line highlighted"></span> 125<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMainInner</span><span class="token punctuation">(</span>imgHandle<span class="token operator">:</span> EfiHandle<span class="token punctuation">,</span> sysTable<span class="token operator">:</span> <span class="token keyword">ptr</span> EFiSystemTable<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token operator">=</span></span> 126<span class="line highlighted"> echo <span class="token string">"Fusion OS Bootloader"</span></span> 127<span class="line highlighted"></span> 128<span class="line highlighted"> <span class="token keyword">var</span> status<span class="token operator">:</span> EfiStatus</span> 129<span class="line highlighted"></span> 130<span class="line highlighted"> <span class="token comment"># get the LoadedImage protocol from the image handle</span></span> 131<span class="line highlighted"> <span class="token keyword">var</span> loadedImage<span class="token operator">:</span> <span class="token keyword">ptr</span> EfiLoadedImageProtocol</span> 132<span class="line highlighted"></span> 133<span class="line highlighted"> consoleOut <span class="token string">"boot: Acquiring LoadedImage protocol"</span></span> 134<span class="line highlighted"> checkStatus uefi<span class="token operator">.</span>sysTable<span class="token operator">.</span>bootServices<span class="token operator">.</span><span class="token function">handleProtocol</span><span class="token punctuation">(</span></span> 135<span class="line highlighted"> imgHandle<span class="token punctuation">,</span> EfiLoadedImageProtocolGuid<span class="token punctuation">,</span> <span class="token function">cast[ptr pointer]</span><span class="token punctuation">(</span><span class="token keyword">addr</span> loadedImage<span class="token punctuation">)</span></span> 136<span class="line highlighted"> <span class="token punctuation">)</span></span> 137<span class="line"><span class="token operator">...</span></span> 138<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Let's compile and run everything using <code>just run</code>. We should see the following output (The colored output is for nice visual
138s only. I didn't show it in the code above; I'm leaving it as an exercise for the reader):</p><p><img src="`+l+`" alt="Boot - LoadedImage"></p><h2 id="file-system" tabindex="-1"><a class="header-anchor" href="#file-system"><span>File system</span></a></h2><p>Now that we have the <code>EfiLoadedImageProtocol</code> device handle, we can get the <code>EfiSimpleFileSystemProtocol</code> of that device. Let's define the <code>EfiSimpleFileSystemProtocol</code> type and the corresponding GUID in <code>src/common/uefi.nim</code>.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/common/uefi.nim</span></span> 139<span class="line"></span> 140<span class="line"><span class="token keyword">type</span></span> 141<span class="line"> EfiSimpleFileSystemProtocol<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 142<span class="line"> revision<span class="token operator">*:</span> uint64</span> 143<span class="line"> openVolume<span class="token operator">*:</span> pointer</span> 144<span class="line"></span> 145<span class="line"><span class="token keyword">const</span></span> 146<span class="line"> EfiSimpleFileSystemProtocolGuid<span class="token operator">*</span> <span class="token operator">=</span> <span class="token function">EfiGuid</span><span class="token punctuation">(</span></span> 147<span class="line"> data1<span class="token operator">:</span> <span class="token number">0x964e5b22'u32</span><span class="token punctuation">,</span> data2<span class="token operator">:</span> <span class="token number">0x6459</span><span class="token punctuation">,</span> data3<span class="token operator">:</span> <span class="token number">0x11d2</span><span class="token punctuation">,</span></span> 148<span class="line"> data4<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0x8e</span><span class="token punctuation">,</span> <span class="token number">0x39</span><span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">0xa0</span><span class="token punctuation">,</span> <span class="token number">0xc9</span><span class="token punctuation">,</span> <span class="token number">0x69</span><span class="token punctuation">,</span> <span class="token number">0x72</span><span class="token punctuation">,</span> <span class="token number">0x3b</span><span class="token punctuation">]</span></span> 149<span class="line"> <span class="token punctuation">)</span></span> 150<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Now we're ready to get the <code>EfiSimpleFileSystemProtocol</code> from the <code>EfiLoadedImageProtocol</code> device handle.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMainInner</span><span class="token punctuation">(</span>imgHandle<span class="token operator">:</span> EfiHandle<span class="token punctuation">,</span> sysTable<span class="token operator">:</span> <span class="token keyword">ptr</span> EFiSystemTable<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token operator">=</span></span> 151<span class="line"> <span class="token operator">...</span></span> 152<span class="line"></span> 153<span class="line highlighted"> <span class="token comment"># get the FileSystem protocol from the device handle</span></span> 154<span class="line highlighted"> <span class="token keyword">var</span> fileSystem<span class="token operator">:</span> <span class="token keyword">ptr</span> EfiSimpleFileSystemProtocol</span> 155<span class="line highlighted"></span> 156<span class="line highlighted"> consoleOut <span class="token string">"boot: Acquiring SimpleFileSystem protocol"</span></span> 157<span class="line highlighted"> checkStatus uefi<span class="token operator">.</span>sysTable<span class="token operator">.</span>bootServices<span class="token operator">.</span><span class="token function">handleProtocol</span><span class="token punctuation">(</span></span> 158<span class="line highlighted">
158 loadedImage<span class="token operator">.</span>deviceHandle<span class="token punctuation">,</span> EfiSimpleFileSystemProtocolGuid<span class="token punctuation">,</span> <span class="token function">cast[ptr pointer]</span><span class="token punctuation">(</span><span class="token keyword">addr</span> fileSystem<span class="token punctuation">)</span></span> 159<span class="line highlighted"> <span class="token punctuation">)</span></span> 160<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>If we compile and run we should see the following output:</p><p><img src="`+o+`" alt="Alt text"></p><h2 id="root-directory" tabindex="-1"><a class="header-anchor" href="#root-directory"><span>Root directory</span></a></h2><p>Next, we need to get the <code>EfiFileInfo</code> representing the root directory of the file system. Let's define the <code>EfiFileInfo</code> type (we also need to define the <code>EfiTime</code> type, which is used in <code>EfiFileInfo</code>) .</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/common/uefi.nim</span></span> 161<span class="line"></span> 162<span class="line"><span class="token keyword">type</span></span> 163<span class="line"> EfiFileInfo<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 164<span class="line"> size<span class="token operator">*:</span> uint64</span> 165<span class="line"> fileSize<span class="token operator">*:</span> uint64</span> 166<span class="line"> physicalSize<span class="token operator">*:</span> uint64</span> 167<span class="line"> createTime<span class="token operator">*:</span> EfiTime</span> 168<span class="line"> lastAccessTime<span class="token operator">*:</span> EfiTime</span> 169<span class="line"> modificationTime<span class="token operator">*:</span> EfiTime</span> 170<span class="line"> attribute<span class="token operator">*:</span> uint64</span> 171<span class="line"> fileName<span class="token operator">*:</span> array<span class="token punctuation">[</span><span class="token number">256</span><span class="token punctuation">,</span> Utf16Char<span class="token punctuation">]</span></span> 172<span class="line"></span> 173<span class="line"> EfiTime<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 174<span class="line"> year<span class="token operator">*:</span> uint16</span> 175<span class="line"> month<span class="token operator">*:</span> uint8</span> 176<span class="line"> day<span class="token operator">*:</span> uint8</span> 177<span class="line"> hour<span class="token operator">*:</span> uint8</span> 178<span class="line"> minute<span class="token operator">*:</span> uint8</span> 179<span class="line"> second<span class="token operator">*:</span> uint8</span> 180<span class="line"> pad1<span class="token operator">*:</span> uint8</span> 181<span class="line"> nanosecond<span class="token operator">*:</span> uint32</span> 182<span class="line"> timeZone<span class="token operator">*:</span> int16</span> 183<span class="line"> daylight<span class="token operator">*:</span> uint8</span> 184<span class="line"> pad2<span class="token operator">*:</span> uint8</span> 185<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>The <code>fileName</code> field in the UEFI spec is a C <a href="https://en.wikipedia.org/wiki/Flexible_array_member" target="_blank" rel="noopener noreferrer">flexible array member</a>, which is not supported in Nim. So I'm using a fixed size array here.</p><p>Let's use the <code>openVolume</code> function of the <code>EfiSimpleFileSystemProtocol</code> to get the <code>EfiFileInfo</code> of the root directory. First, we need to update the signature of <code>openVolume</code>, which also requires defining the <code>EfiFileProtocol</code> type.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/common/uefi.nim</span></span> 186<span class="line"></span> 187<span class="line"><span class="token keyword">type</span></span> 188<span class="line"> EfiSimpleFileSystemProtocol<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 189<span class="line"> revision<span class="token operator">*:</span> uint64</span> 190<span class="line highlighted"> openVolume<span class="token operator">*:</span> <span class="token function">proc</span> <span class="token punctuation">(</span>this<span class="token operator">:</span> <span class="token keyword">ptr</span> EfiSimpleFileSystemProtocol<span class="token punctuation">,</span> root<span class="token operator">:</span> <span class="token keyword">ptr</span> <span class="token keyword">ptr</span> EfiFileProtocol<span class="token punctuation">)</span><span class="token operator">:</span></span> 191<span class="line highlighted"> EfiStatus <span class="token punctuation">{.</span>cdecl<span class="token punctuation">.}</span></span> 192<span class="line highlighted"></span> 193<span class="line highlighted"> EfiFileProtocol<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 194<span class="line highlighted"> revision<span class="token operator">*:</span> uint64</span> 195<span class="line highlighted"> open<span class="token operator">*:</span> pointer</span> 196<span class="line highlighted"> close<span class="token operator">*:</span> pointer</span> 197<span class="line highlighted"> delete<span class="token operator">*:</span> pointer</span> 198<span class="line highlighted"> read<span class="token operator">*:</span> pointer</span> 199<span class="line highlighted"> write<span class="token operator">*:</span> pointer</span> 200<span class="line highlighted"> getPosition<span class="token operator">*:</span> pointer</span> 201<span class="line highlighted"> setPosition<span class="token operator">*:</span> pointer</span> 202<span class="line highlighted"> getInfo<span class="token operator">*:</span> pointer</span> 203<span class="line highlighted"> setInfo<span class="token operator">*:</span> pointer</span> 204<span class="line highlighted"> flush<span class="token operator">*:</span> pointer</span> 205<span class="line highlighted"> openEx<span class="token operator">*:</span> pointer</span> 206<span class="line highlighted"> readEx<span class="token operator">*:</span> pointer</span> 207<span class="line highlighted"> writeEx<span class="token operator">*:</span> pointer</span> 208<span class="line highlighted"> flushEx<span class="token operator">*:</span> pointer</span> 209<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Now we're ready to get the <code>EfiFileInfo</code> of the root directory.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/boot/bootx64.nim</span></span> 210<span class="line"></span> 211<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMainInner</span><span class="token punctuation">(</span>imgHandle<span class="token operator">:</span> EfiHandle<span class="token punctuation">,</span> sysTable<span class="token operator">:</span> <span class="token keyword">ptr</span>
211 EFiSystemTable<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token operator">=</span></span> 212<span class="line"> <span class="token operator">...</span></span> 213<span class="line"></span> 214<span class="line highlighted"> <span class="token comment"># open the root directory</span></span> 215<span class="line highlighted"> <span class="token keyword">var</span> rootDir<span class="token operator">:</span> <span class="token keyword">ptr</span> EfiFileProtocol</span> 216<span class="line highlighted"></span> 217<span class="line highlighted"> consoleOut <span class="token string">"boot: Opening root directory"</span></span> 218<span class="line highlighted"> checkStatus fileSystem<span class="token operator">.</span><span class="token function">openVolume</span><span class="token punctuation">(</span>fileSystem<span class="token punctuation">,</span> <span class="token keyword">addr</span> rootDir<span class="token punctuation">)</span></span> 219<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>This should also compile and run successfully.</p><h2 id="kernel-image-file" tabindex="-1"><a class="header-anchor" href="#kernel-image-file"><span>Kernel image file</span></a></h2><p>We have the <code>EfiFileProtocol</code> of the root directory, so we can use it to get the <code>EfiFileProtocol</code> of the kernel image file, given its path. To open the kernel file, we'll need to define the <code>open</code> function of the <code>EfiFileProtocol</code>.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/common/uefi.nim</span></span> 220<span class="line"></span> 221<span class="line"><span class="token keyword">type</span></span> 222<span class="line"> EfiFileProtocol<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 223<span class="line"> revision<span class="token operator">*:</span> uint64</span> 224<span class="line highlighted"> open<span class="token operator">*:</span> <span class="token function">proc</span> <span class="token punctuation">(</span></span> 225<span class="line highlighted"> this<span class="token operator">:</span> <span class="token keyword">ptr</span> EfiFileProtocol<span class="token punctuation">,</span></span> 226<span class="line highlighted"> newHandle<span class="token operator">:</span> <span class="token keyword">ptr</span> <span class="token keyword">ptr</span> EfiFileProtocol<span class="token punctuation">,</span></span> 227<span class="line highlighted"> fileName<span class="token operator">:</span> WideCString<span class="token punctuation">,</span></span> 228<span class="line highlighted"> openMode<span class="token operator">:</span> uint64<span class="token punctuation">,</span></span> 229<span class="line highlighted"> attributes<span class="token operator">:</span> uint64</span> 230<span class="line highlighted"> <span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token punctuation">{.</span>cdecl<span class="token punctuation">.}</span></span> 231<span class="line"> <span class="token operator">...</span></span> 232<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Now we're ready to open the kernel file.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/boot/bootx64.nim</span></span> 233<span class="line"></span> 234<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMainInner</span><span class="token punctuation">(</span>imgHandle<span class="token operator">:</span> EfiHandle<span class="token punctuation">,</span> sysTable<span class="token operator">:</span> <span class="token keyword">ptr</span>
234 EFiSystemTable<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token operator">=</span></span> 235<span class="line"> <span class="token operator">...</span></span> 236<span class="line"></span> 237<span class="line highlighted"> <span class="token comment"># open the kernel file</span></span> 238<span class="line highlighted"> <span class="token keyword">var</span> kernelFile<span class="token operator">:</span> <span class="token keyword">ptr</span> EfiFileProtocol</span> 239<span class="line highlighted"> <span class="token keyword">let</span> kernelPath <span class="token operator">=</span> <span class="token string">W"efi\\fusion\\kernel.bin"</span></span> 240<span class="line highlighted"></span> 241<span class="line highlighted"> consoleOut <span class="token string">"boot: Opening kernel file: "</span></span> 242<span class="line highlighted"> consoleOut kernelPath</span> 243<span class="line highlighted"> checkStatus rootDir<span class="token operator">.</span><span class="token function">open</span><span class="token punctuation">(</span>rootDir<span class="token punctuation">,</span> <span class="token keyword">addr</span> kernelFile<span class="token punctuation">,</span> kernelPath<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span></span> 244<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>This should also compile and run successfully.</p><p><img src="`+p+`" alt="Boot - Open kernel file"></p><p>Let's now get the size of the kernel file. To do so, we'll need to define the <code>getInfo</code> function of the <code>EfiFileProtocol</code>. We'll also need to define <code>EfiFileInfoGuid</code>.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/common/uefi.nim</span></span> 245<span class="line"></span> 246<span class="line"><span class="token keyword">type</span></span> 247<span class="line"> EfiFileProtocol<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 248<span class="line"> <span class="token operator">...</span></span> 249<span class="line highlighted"> getInfo<span class="token operator">*:</span> <span class="token function">proc</span> <span class="token punctuation">(</span></span> 250<span class="line highlighted"> this<span class="token operator">:</span> <span class="token keyword">ptr</span> EfiFileProtocol<span class="token punctuation">,</span></span> 251<span class="line highlighted"> infoType<span class="token operator">:</span> <span class="token keyword">ptr</span> EfiGuid<span class="token punctuation">,</span></span> 252<span class="line highlighted"> infoSize<span class="token operator">:</span> <span class="token keyword">ptr</span> uint<span class="token punctuation">,</span></span> 253<span class="line highlighted"> info<span class="token operator">:</span> pointer</span> 254<span class="line highlighted"> <span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token punctuation">{.</span>cdecl<span class="token punctuation">.}</span></span> 255<span class="line"> <span class="token operator">...</span></span> 256<span class="line"></span> 257<span class="line"><span class="token keyword">const</span></span> 258<span class="line highlighted"> EfiFileInfoGuid<span class="token operator">*</span> <span class="token operator">=</span> <span class="token function">EfiGuid</span><span class="token punctuation">(</span></span> 259<span class="line highlighted"> data1<span class="token operator">:</span> <span class="token number">0x09576e92'u32</span><span class="token punctuation">,</span> data2<span class="token operator">:</span> <span class="token number">0x6d3f</span><span class="token punctuation">,</span> data3<span class="token operator">:</span> <span class="token number">0x11d2</span><span class="token punctuation">,</span></span> 260<span class="line highlighted"> data4<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0x8e</span><span class="token punctuation">,</span> <span class="token number">0x39</span><span class="token punctuation">,</span> <span class="token number">0x00</span><span class="token punctuation">,</span> <span class="token number">0xa0</span><span class="token punctuation">,</span> <span class="token number">0xc9</span><span class="token punctuation">,</span> <span class="token number">0x69</span><span class="token punctuation">,</span> <span class="token number">0x72</span><span class="token punctuation">,</span> <span class="token number">0x3b</span><span class="token punctuation">]</span></span> 261<span class="line highlighted"> <span class="token punctuation">)</span></span> 262<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Let's call the <code>getInfo</code> function on the kernel file.</p><div class="language-nim line-numbers-mode" data-highlighter="prismjs" data-ext="nim" data-title="nim"><pre><code><span class="line"><span class="token comment"># src/boot/bootx64.nim</span></span> 263<span class="line"></span> 264<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMainInner</span><span class="token punctuation">(</span>imgHandle<span class="token operator">:</span> EfiHandle<span class="token punctuation">,</span> sysTable<span class="token operator">:</span> <span class="token keyword">ptr</span>
264 EFiSystemTable<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token operator">=</span></span> 265<span class="line"> <span class="token operator">...</span></span> 266<span class="line"></span> 267<span class="line highlighted"> <span class="token comment"># get kernel file size</span></span> 268<span class="line highlighted"> <span class="token keyword">var</span> kernelInfo<span class="token operator">:</span> EfiFileInfo</span> 269<span class="line highlighted"> <span class="token keyword">var</span> kernelInfoSize <span class="token operator">=</span> <span class="token function">sizeof</span><span class="token punctuation">(</span>EfiFileInfo<span class="token punctuation">)</span><span class="token operator">.</span>uint</span> 270<span class="line highlighted"></span> 271<span class="line highlighted"> consoleOut <span class="token string">"boot: Getting kernel file info"</span></span> 272<span class="line highlighted"> checkStatus kernelFile<span class="token operator">.</span><span class="token function">getInfo</span><span class="token punctuation">(</span>kernelFile<span class="token punctuation">,</span> <span class="token keyword">addr</span> EfiFileInfoGuid<span class="token punctuation">,</span> <span class="token keyword">addr</span> kernelInfoSize<span class="token punctuation">,</span> <span class="token keyword">addr</span> kernelInfo<span class="token punctuation">)</span></span> 273<span class="line highlighted"> echo <span class="token operator">&</span><span class="token string">"boot: Kernel file size: {kernelInfo.fileSize} bytes"</span></span> 274<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>If all goes well, we should see the kernel file size in the output:</p><p><img src="`+t+'" alt="Boot - Kernel file size"></p><p>Great! The kernel image size is what we expect (around 1.1 MiB). In the next section we'll continue to allocate memory for the kernel image and read it into memory.</p>',53)]))}const m=s(c,[["render",r],["__file","08-loading-the-kernel-p1.html.vue"]]),v=JSON.parse(`{"path":"/osdev/08-loading-the-kernel-p1.html","title":"Loading the Kernel (Part 1)","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"UEFI Boot Services","slug":"uefi-boot-services","link":"#uefi-boot-services","children":[]},{"level":2,"title":"Boot device handle","slug":"boot-device-handle","link":"#boot-device-handle","children":[]},{"level":2,"title":"File system","slug":"file-system","link":"#file-system","children":[]},{"level":2,"title":"Root directory","slug":"root-directory","link":"#root-directory","children":[]},{"level":2,"title":"Kernel image file","slug":"kernel-image-file","link":"#kernel-image-file","children":[]}],"git":{"updatedTime":1744638230000},"filePathRelative":"osdev/08-loading-the-kernel-p1.md","excerpt":"\\n<p>In the last section we built a raw binary kernel image. We'll pick up where we left off in\\nthe bootloader and load the kernel image into memory. We'll rely on UEFI Boot Services to\\ndo so.</p>\\n<h2>UEFI Boot Services</h2>\\n<p>UEFI Boot Services provides a number of services to help us, including accessing the file\\nsystem, getting information about a file, allocating memory, and reading a file into\\nmemory. Here's the plan:</p>"}`);export{m as comp,v as data};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.