PageSourceSearch

https://0xc0ffee.netlify.app/assets/06-bootloader-p2.html-Bvk_BiUf.js

js 0xc0ffee.netlify.app collected 2026-10-03 10:23:17 UTC 43,612 bytes, 171 lines download raw bytes

1import{_ as s,c as a,e,o as t}from"./app-CjUkjRdW.js";const p="/assets/bootloader-hello-world-BDspxe1F.png",i="/assets/catching-exceptions-1-Thl79MYG.png",o="/assets/catching-exceptions-2-DuxMgHo2.png",l={};function c(r,n){return t(),a("div",null,n[0]||(n[0]=[e(`<h1 id="uefi-bootloader-part-2" tabindex="-1"><a class="header-anchor" href="#uefi-bootloader-part-2"><span>UEFI Bootloader (Part 2)</span></a></h1><p>In the previous section, we wrote a simple UEFI entry point for the bootloader. In this section, we&#39;ll use the UEFI API provided to us through the UEFI system table to print a simple message to the screen.</p><h2 id="uefi-system-table" tabindex="-1"><a class="header-anchor" href="#uefi-system-table"><span>UEFI System Table</span></a></h2><p>The UEFI system table is a data structure that is passed to the bootloader by the UEFI firmware. It contains pointers to various UEFI services, such as the console, file system, and memory management. We&#39;ll start by defining the system table in <code>src/bootx64.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/bootx64.nim</span></span>
2<span class="line"></span>
3<span class="line"><span class="token keyword">type</span></span>
4<span class="line">  EfiStatus <span class="token operator">=</span> uint</span>
5<span class="line"></span>
6<span class="line">  EfiHandle <span class="token operator">=</span> pointer</span>
7<span class="line"></span>
8<span class="line highlighted">  EfiTableHeader <span class="token operator">=</span> <span class="token keyword">object</span></span>
9<span class="line highlighted">    signature<span class="token operator">:</span> uint64</span>
10<span class="line highlighted">    revision<span class="token operator">:</span> uint32</span>
11<span class="line highlighted">    headerSize<span class="token operator">:</span> uint32</span>
12<span class="line highlighted">    crc32<span class="token operator">:</span> uint32</span>
13<span class="line highlighted">    reserved<span class="token operator">:</span> uint32</span>
14<span class="line highlighted"></span>
15<span class="line highlighted">  EfiSystemTable <span class="token operator">=</span> <span class="token keyword">object</span></span>
16<span class="line highlighted">    header<span class="token operator">:</span> EfiTableHeader</span>
17<span class="line highlighted">    firmwareVendor<span class="token operator">:</span> WideCString</span>
18<span class="line highlighted">    firmwareRevision<span class="token operator">:</span> uint32</span>
19<span class="line highlighted">    consoleInHandle<span class="token operator">:</span> EfiHandle</span>
20<span class="line highlighted">    conIn<span class="token operator">:</span> pointer</span>
21<span class="line highlighted">    consoleOutHandle<span class="token operator">:</span> EfiHandle</span>
22<span class="line highlighted">    conOut<span class="token operator">:</span> <span class="token keyword">ptr</span> SimpleTextOutputProtocol</span>
23<span class="line highlighted">    standardErrorHandle<span class="token operator">:</span> EfiHandle</span>
24<span class="line highlighted">    stdErr<span class="token operator">:</span> SimpleTextOutputProtocol</span>
25<span class="line highlighted">    runtimeServices<span class="token operator">:</span> pointer</span>
26<span class="line highlighted">    bootServices<span class="token operator">:</span> pointer</span>
27<span class="line highlighted">    numTableEntries<span class="token operator">:</span> uint</span>
28<span class="line highlighted">    configTable<span class="token operator">:</span> pointer</span>
29<span class="line highlighted">  </span>
30<span class="line highlighted">  SimpleTextOutputProtocol <span class="token operator">=</span> <span class="token keyword">object</span></span>
31<span class="line highlighted">    reset<span class="token operator">:</span> pointer</span>
32<span class="line highlighted">    outputString<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> SimpleTextOutputProtocol<span class="token punctuation">,</span> str<span class="token operator">:</span> WideCString<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token punctuation">{.</span>cdecl<span class="token punctuation">.}</span></span>
33<span class="line highlighted">    testString<span class="token operator">:</span> pointer</span>
34<span class="line highlighted">
34    queryMode<span class="token operator">:</span> pointer</span>
35<span class="line highlighted">    setMode<span class="token operator">:</span> pointer</span>
36<span class="line highlighted">    setAttribute<span class="token operator">:</span> pointer</span>
37<span class="line highlighted">    clearScreen<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> SimpleTextOutputProtocol<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token punctuation">{.</span>cdecl<span class="token punctuation">.}</span></span>
38<span class="line highlighted">    setCursorPos<span class="token operator">:</span> pointer</span>
39<span class="line highlighted">    enableCursor<span class="token operator">:</span> pointer</span>
40<span class="line highlighted">    mode<span class="token operator">:</span> <span class="token keyword">ptr</span> pointer</span>
41<span class="line"></span>
42<span class="line"><span class="token keyword">const</span></span>
43<span class="line">  EfiSuccess <span class="token operator">=</span> <span class="token number">0</span></span>
44<span class="line">  EfiLoadError <span class="token operator">=</span> <span class="token number">1</span></span>
45<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></div><p>We&#39;re particularly interested in the <code>conOut</code> field, which is a pointer to the console output interface <code>SimpleTextOutputProtocol</code>. We&#39;ll use this to clear the screen (using the <code>clearScreen</code> function) and print to the screen (using the <code>outputString</code> function).</p><h2 id="printing-to-the-screen" tabindex="-1"><a class="header-anchor" href="#printing-to-the-screen"><span>Printing to the Screen</span></a></h2><p>Let&#39;s start by clearing the screen. To avoid returning to the UEFI shell, we&#39;ll call the <code>quit</code> function, which eventually calls the <code>exit</code> function we implemented earlier, which halts the CPU.</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/bootx64.nim</span></span>
46<span class="line"><span class="token operator">...</span></span>
47<span class="line"></span>
48<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMain</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>
48 EFiSystemTable<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
49<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
50<span class="line highlighted">  <span class="token keyword">discard</span> sysTable<span class="token operator">.</span>conOut<span class="token operator">.</span><span class="token function">clearScreen</span><span class="token punctuation">(</span>sysTable<span class="token operator">.</span>conOut<span class="token punctuation">)</span></span>
51<span class="line">  <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
52<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></div><p>When we compile and load this in QEMU, we see a blank screen, as expected.</p><p>Next, let&#39;s print a simple message to the screen. We&#39;ll use the <code>outputString</code> function, which takes a pointer to a null-terminated UTF-16 string. Nim supports UTF-16 strings through the <code>Utf16Char</code> and <code>WideCString</code> types. Before we start using <code>WideCString</code>, I want to highlight a difference in how Nim declares this type in the presence of a <code>nimv2</code> flag. Without this flag, Nim defines <code>WideCString</code> as a <code>ref UncheckedArray[Utf16Char]</code>. With the <code>nimv2</code> flag, Nim defines <code>WideCString</code> as a <code>ptr UncheckedArray[Utf16Char]</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"># nim-2.0.0/lib/std/widestrs.nim</span></span>
53<span class="line"></span>
54<span class="line"><span class="token keyword">when</span> <span class="token function">defined</span><span class="token punctuation">(</span>nimv2<span class="token punctuation">)</span><span class="token operator">:</span></span>
55<span class="line">  <span class="token keyword">type</span></span>
56<span class="line">    WideCString<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">ptr</span> UncheckedArray<span class="token punctuation">[</span>Utf16Char<span class="token punctuation">]</span></span>
57<span class="line">    WideCStringObj<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">object</span></span>
58<span class="line">      bytes<span class="token operator">:</span> int</span>
59<span class="line">      data<span class="token operator">:</span> WideCString</span>
60<span class="line"> <span class="token operator">...</span></span>
61<span class="line">    <span class="token keyword">converter</span> <span class="token function">toWideCString<span class="token operator">*</span></span><span class="token punctuation">(</span>x<span class="token operator">:</span> WideCStringObj<span class="token punctuation">)</span><span class="token operator">:</span> WideCString <span class="token punctuation">{.</span>inline<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
62<span class="line">      result <span class="token operator">=</span> x<span class="token operator">.</span>data</span>
63<span class="line"></span>
64<span class="line"><span class="token keyword">else</span><span class="token operator">:</span></span>
65<span class="line">  <span class="token operator">...</span></span>
66<span class="line">  <span class="token keyword">type</span></span>
67<span class="line">    WideCString<span class="token operator">*</span> <span class="token operator">=</span> <span class="token keyword">ref</span> UncheckedArray<span class="token punctuation">[</span>Utf16Char<span class="token punctuation">]</span></span>
68<span class="line">    WideCStringObj<span class="token operator">*</span> <span class="token operator">=</span> WideCString</span>
69<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></div><p>Since we&#39;re going to pass a pointer to a null-terminated UTF-16 string to <code>outputString</code>, we need to use the <code>ptr</code> version of <code>WideCString</code>. So let&#39;s add the <code>nimv2</code> flag to our <code>nim.cfg</code>:</p><div class="language-properties line-numbers-mode" data-highlighter="prismjs" data-ext="properties" data-title="properties"><pre><code><span class="line"><span class="token comment"># nim.cfg</span></span>
70<span class="line"><span class="token key attr-name">-d</span><span class="token punctuation">:</span><span class="token value attr-value">nimv2</span></span>
71<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></div><p>We create a wide string using <code>newWideCString</code> (which returns a <code>WideCStringObj</code>), use the <code>toWideCString</code> converter to get access to the underlying data buffer, and then pass it to <code>outputString</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/bootx64.nim</span></span>
72<span class="line"></span>
73<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMain</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>
73 EFiSystemTable<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
74<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
75<span class="line"></span>
76<span class="line highlighted">  <span class="token keyword">let</span> msg <span class="token operator">=</span> <span class="token function">newWideCString</span><span class="token punctuation">(</span><span class="token string">&quot;Hello, world!\\n&quot;</span><span class="token punctuation">)</span><span class="token operator">.</span>toWideCString</span>
77<span class="line highlighted"></span>
78<span class="line highlighted">  <span class="token keyword">discard</span> sysTable<span class="token operator">.</span>conOut<span class="token operator">.</span><span class="token function">clearScreen</span><span class="token punctuation">(</span>sysTable<span class="token operator">.</span>conOut<span class="token punctuation">)</span></span>
79<span class="line highlighted">  <span class="token keyword">discard</span> sysTable<span class="token operator">.</span>conOut<span class="token operator">.</span><span class="token function">outputString</span><span class="token punctuation">(</span>sysTable<span class="token operator">.</span>conOut<span class="token punctuation">,</span> msg<span class="token punctuation">)</span></span>
80<span class="line"></span>
81<span class="line">  <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
82<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></div><p>When we compile and load this in QEMU, we see the message printed to the screen, as expected.</p><p><img src="`+p+`" alt="Bootloader Hello World"></p><p>Let&#39;s make it easier to create a wide string by adding a <code>W</code> prefix operator to <code>string</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/uefi.nim</span></span>
83<span class="line"></span>
84<span class="line"><span class="token keyword">proc</span> <span class="token function">W<span class="token operator">*</span></span><span class="token punctuation">(</span>str<span class="token operator">:</span> string<span class="token punctuation">)</span><span class="token operator">:</span> WideCString <span class="token operator">=</span></span>
85<span class="line">  <span class="token function">newWideCString</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token operator">.</span>toWideCString</span>
86<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></div><p>Now we can create a wide string using <code>W</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/bootx64.nim</span></span>
87<span class="line"></span>
88<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMain</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>
88 EFiSystemTable<span class="token punctuation">)</span><span class="token operator">:</span> EfiStatus <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
89<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
90<span class="line"></span>
91<span class="line">  <span class="token keyword">discard</span> sysTable<span class="token operator">.</span>conOut<span class="token operator">.</span><span class="token function">clearScreen</span><span class="token punctuation">(</span>sysTable<span class="token operator">.</span>conOut<span class="token punctuation">)</span></span>
92<span class="line highlighted">  <span class="token keyword">discard</span> sysTable<span class="token operator">.</span>conOut<span class="token operator">.</span><span class="token function">outputString</span><span class="token punctuation">(</span>sysTable<span class="token operator">.</span>conOut<span class="token punctuation">,</span> <span class="token string">W&quot;Hello, world!\\n&quot;</span><span class="token punctuation">)</span></span>
93<span class="line"></span>
94<span class="line">  <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
95<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></div><h2 id="using-echo" tabindex="-1"><a class="header-anchor" href="#using-echo"><span>Using <code>echo</code></span></a></h2><p>Preparing a UTF-16 string and calling <code>outputString</code> every time we want to print to the screen is tedious. Ideally, we should be able to use the built-in <code>echo</code> procedure to print to the screen. This requires us to define a <code>stdout</code> file descriptor and implement <code>fwrite</code> to use the UEFI <code>outputString</code> function. But instead of making the <code>libc</code> module deal with UEFI internals, we&#39;ll create a new module called <code>uefi</code> to handle this. We&#39;ll also move all the UEFI types and constants to this module. In the process, we&#39;ll mark all types, constants, and vars as public so that they can be used by other modules.</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/uefi.nim</span></span>
96<span class="line"></span>
97<span class="line"><span class="token keyword">type</span></span>
98<span class="line">  EfiStatus<span class="token operator">*</span> <span class="token operator">=</span> uint</span>
99<span class="line">  <span class="token operator">...</span></span>
100<span class="line"></span>
101<span class="line highlighted"><span class="token keyword">var</span></span>
102<span class="line highlighted">  sysTable<span class="token operator">*:</span> <span class="token keyword">ptr</span> EfiSystemTable</span>
103<span class="line highlighted"></span>
104<span class="line highlighted"><span class="token keyword">proc</span> <span class="token function">consoleClear<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span></span>
105<span class="line highlighted">  assert <span class="token operator">not</span> sysTable<span class="token operator">.</span>isNil</span>
106<span class="line highlighted">  <span class="token keyword">discard</span> sysTable<span class="token operator">.</span>conOut<span class="token operator">.</span><span class="token function">clearScreen</span><span class="token punctuation">(</span>sysTable<span class="token operator">.</span>conOut<span class="token punctuation">)</span></span>
107<span class="line highlighted"></span>
108<span class="line highlighted"><span class="token keyword">proc</span> <span class="token function">consoleOut<span class="token operator">*</span></span><span class="token punctuation">(</span>str<span class="token operator">:</span> string<span class="token punctuation">)</span> <span class="token operator">=</span></span>
109<span class="line highlighted">  assert <span class="token operator">not</span> sysTable<span class="token operator">.</span>isNil</span>
110<span class="line highlighted">  <span class="token keyword">discard</span> sysTable<span class="token operator">.</span>conOut<span class="token operator">.</span><span class="token function">outputString</span><span class="token punctuation">(</span>sysTable<span class="token operator">.</span>conOut<span class="token punctuation">,</span> <span class="token function">W</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">)</span></span>
111<span class="line highlighted"></span>
112<span class="line highlighted"><span class="token keyword">proc</span> <span class="token function">consoleError<span class="token operator">*</span></span><span class="token punctuation">(</span>str<span class="token operator">:</span> string<span class="token punctuation">)</span> <span class="token operator">=</span></span>
113<span class="line highlighted">  assert <span class="token operator">not</span> sysTable<span class="token operator">.</span>isNil</span>
114<span class="line highlighted">  <span class="token keyword">discard</span> sysTable<span class="token operator">.</span>stdErr<span class="token operator">.</span><span class="token function">outputString</span><span class="token punctuation">(</span>sysTable<span class="token operator">.</span>stdErr<span class="token punctuation">,</span> <span class="token function">W</span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">)</span></span>
115<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></div><p>We&#39;ll initialize the <code>sysTable</code> variable in <code>src/bootx64.nim</code> later. Let&#39;s implement <code>fwrite</code> to use the <code>consoleOut</code> procedure we just defined. Notice that we don&#39;t use the <code>stream</code> argument to differentiate between <code>stdout</code> and <code>stderr</code> here (since they&#39;re both <code>nil</code> for now). We&#39;ll leave that for later.</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/libc.nim</span></span>
116<span class="line"></span>
117<span class="line"><span class="token keyword">
117import</span> uefi</span>
118<span class="line"></span>
119<span class="line"><span class="token keyword">proc</span> <span class="token function">fwrite<span class="token operator">*</span></span><span class="token punctuation">(</span>buf<span class="token operator">:</span> const_pointer<span class="token punctuation">,</span> size<span class="token operator">:</span> csize_t<span class="token punctuation">,</span> count<span class="token operator">:</span> csize_t<span class="token punctuation">,</span> stream<span class="token operator">:</span> File<span class="token punctuation">)</span><span class="token operator">:</span> csize_t <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
120<span class="line highlighted">  <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token operator">$</span><span class="token function">cast[cstring]</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span></span>
121<span class="line highlighted">  <span class="token function">consoleOut</span><span class="token punctuation">(</span>output<span class="token punctuation">)</span></span>
122<span class="line">  <span class="token keyword">return</span> count</span>
123<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></div><p>Now let&#39;s update <code>src/bootx64.nim</code> to initialize the <code>sysTable</code> variable and call <code>echo</code> to print to the screen.</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/bootx64.nim</span></span>
124<span class="line"></span>
125<span class="line"><span class="token keyword">import</span> uefi</span>
126<span class="line"><span class="token operator">...</span></span>
127<span class="line"></span>
128<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMain</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 punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
129<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
130<span class="line highlighted">  uefi<span class="token operator">.</span>sysTable <span class="token operator">=</span> sysTable</span>
131<span class="line"></span>
132<span class="line highlighted">  <span class="token function">consoleClear</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
133<span class="line highlighted">  echo <span class="token string">&quot;Hello, world!&quot;</span></span>
134<span class="line"></span>
135<span class="line">  <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
136<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>When we compile and load this in QEMU, we still see the message printed to the screen, as expected.</p><h2 id="handling-exceptions" tabindex="-1"><a class="header-anchor" href="#handling-exceptions"><span>Handling Exceptions</span></a></h2><p>Right now, if an exception is raised we won&#39;t see any output on the screen. In fact, the bootloader will return the default value <code>0</code>, which will cause the firmware boot manager to load next.</p><p>In a normal application, Nim generates a <code>main</code> entry point which executes our top-level code, and then checks for exceptions, and if one was raised it prints the exception message to <code>stderr</code>. There&#39;s an <code>unhandledExceptionHook</code> we can use to set a custom handler, but the issue is that it&#39;s only called when Nim is in charge of generating the <code>main</code> entry point. Since we&#39;re using <code>--noMain:on</code> and providing a custom <code>EfiMain</code> entry point, we need to handle exceptions ourselves.</p><p>We&#39;ll do this by wrapping the code in <code>EfiMain</code> in a <code>try</code> block, and printing the exception message (and the stack trace, if one exists) to the screen if one was raised. To avoid cluttering the <code>try</code> block with a lot of code, we&#39;ll move that code to a new <code>EfiMainInner</code> procedure.</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/bootx64.nim</span></span>
137<span class="line"></span>
138<span class="line highlighted"><span class="token keyword">proc</span> <span class="token function">unhandledException<span class="token operator">*</span></span><span class="token punctuation">(</span>e<span class="token operator">:</span> <span class="token keyword">ref</span> Exception<span class="token punctuation">)</span> <span class="token operator">=</span></span>
139<span class="line highlighted">  echo <span class="token string">&quot;Unhandled exception: &quot;</span> <span class="token operator">&amp;</span>
139 e<span class="token operator">.</span>msg <span class="token operator">&amp;</span> <span class="token string">&quot; [&quot;</span> <span class="token operator">&amp;</span> <span class="token operator">$</span>e<span class="token operator">.</span>name <span class="token operator">&amp;</span> <span class="token string">&quot;]&quot;</span></span>
140<span class="line highlighted">  <span class="token keyword">if</span> e<span class="token operator">.</span>trace<span class="token operator">.</span>len <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token operator">:</span></span>
141<span class="line highlighted">    echo <span class="token string">&quot;Stack trace:&quot;</span></span>
142<span class="line highlighted">    echo <span class="token function">getStackTrace</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span></span>
143<span class="line highlighted">  <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
144<span class="line highlighted"></span>
145<span class="line highlighted"><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>
146<span class="line highlighted">  uefi<span class="token operator">.</span>sysTable <span class="token operator">=</span> sysTable</span>
147<span class="line highlighted">  <span class="token function">consoleClear</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
148<span class="line highlighted"></span>
149<span class="line highlighted">  <span class="token comment"># force an IndexDefect exception</span></span>
150<span class="line highlighted">  <span class="token keyword">let</span> a <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span></span>
151<span class="line highlighted">  <span class="token keyword">let</span> n <span class="token operator">=</span> <span class="token number">5</span></span>
152<span class="line highlighted">  <span class="token keyword">discard</span> a<span class="token punctuation">[</span>n<span class="token punctuation">]</span></span>
153<span class="line"></span>
154<span class="line"><span class="token keyword">proc</span> <span class="token function">EfiMain</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 punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
155<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
156<span class="line"></span>
157<span class="line highlighted">  <span class="token keyword">try</span><span class="token operator">:</span></span>
158<span class="line highlighted">    <span class="token keyword">return</span> <span class="token function">EfiMainInner</span><span class="token punctuation">(</span>imgHandle<span class="token punctuation">,</span> sysTable<span class="token punctuation">)</span></span>
159<span class="line highlighted">  <span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token operator">:</span></span>
160<span class="line highlighted">    <span class="token function">unhandledException</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span></span>
161<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>When we compile and load this in QEMU, we see the exception message and stack trace printed to the screen, but it looks like the newlines are not being printed correctly.</p><p><img src="`+i+`" alt="Catching Exceptions 1"></p><p>The problem is that Nim uses LF as the newline character, but UEFI expects CRLF. We can fix this by modifying the <code>fwrite</code> procedure to split the string into lines, and print a CR after each line.</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/libc.nim</span></span>
162<span class="line"></span>
163<span class="line"><span class="token keyword">
163import</span> std<span class="token operator">/</span>strutils</span>
164<span class="line"></span>
165<span class="line"><span class="token keyword">proc</span> <span class="token function">fwrite</span><span class="token punctuation">(</span>buf<span class="token operator">:</span> const_pointer<span class="token punctuation">,</span> size<span class="token operator">:</span> csize_t<span class="token punctuation">,</span> count<span class="token operator">:</span> csize_t<span class="token punctuation">,</span> stream<span class="token operator">:</span> File<span class="token punctuation">)</span><span class="token operator">:</span> csize_t <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
166<span class="line">  <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token operator">$</span><span class="token function">cast[cstring]</span><span class="token punctuation">(</span>buf<span class="token punctuation">)</span></span>
167<span class="line highlighted">  <span class="token keyword">for</span> line <span class="token operator">in</span> output<span class="token operator">.</span><span class="token function">splitLines</span><span class="token punctuation">(</span>keepEOL <span class="token operator">=</span> true<span class="token punctuation">)</span><span class="token operator">:</span></span>
168<span class="line highlighted">    <span class="token function">consoleOut</span><span class="token punctuation">(</span>line<span class="token punctuation">)</span></span>
169<span class="line highlighted">    <span class="token function">consoleOut</span><span class="token punctuation">(</span><span class="token string">&quot;\\r&quot;</span><span class="token punctuation">)</span></span>
170<span class="line">  <span class="token keyword">return</span> count</span>
171<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><img src="`+o+'" alt="Catching Exceptions 2"></p><p>Much better! We just have to keep in mind that stack traces are available only in debug builds (which is the default). If we compile in release mode, we won&#39;t see the stack trace. But this is great! We now have a way to print to the screen and catch and display unhandled exceptions (so we&#39;re not flying blind).</p><p>The next logical step is to load our kernel from disk, but we don&#39;t have a kernel yet. So we&#39;ll take a short break from the bootloader and start working on the kernel in the next section.</p>',42)]))}const u=s(l,[["render",c],["__file","06-bootloader-p2.html.vue"]]),k=JSON.parse(`{"path":"/osdev/06-bootloader-p2.html","title":"UEFI Bootloader (Part 2)","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"UEFI System Table","slug":"uefi-system-table","link":"#uefi-system-table","children":[]},{"level":2,"title":"Printing to the Screen","slug":"printing-to-the-screen","link":"#printing-to-the-screen","children":[]},{"level":2,"title":"Using echo","slug":"using-echo","link":"#using-echo","children":[]},{"level":2,"title":"Handling Exceptions","slug":"handling-exceptions","link":"#handling-exceptions","children":[]}],"git":{"updatedTime":1744638230000},"filePathRelative":"osdev/06-bootloader-p2.md","excerpt":"\\n<p>In the previous section, we wrote a simple UEFI entry point for the bootloader. In this\\nsection, we'll use the UEFI API provided to us through the UEFI system table to print a\\nsimple message to the screen.</p>\\n<h2>UEFI System Table</h2>\\n<p>The UEFI system table is a data structure that is passed to the bootloader by the UEFI\\nfirmware. It contains pointers to various UEFI services, such as the console, file system,\\nand memory management. We'll start by defining the system table in <code>src/bootx64.nim</code>:</p>"}`);export{u as comp,k 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.