1import{_ as s,c as a,e,o as t}from"./app-CjUkjRdW.js";const i={};function l(p,n){return t(),a("div",null,n[0]||(n[0]=[e(`<h1 id="interrupts" tabindex="-1"><a class="header-anchor" href="#interrupts"><span>Interrupts</span></a></h1><p>When the CPU encounters an error, e.g. a division by zero or a page fault, it will raise an exception, which is a kind of interrupt. The CPU consults a table, called the <strong>Interrupt Descriptor Table</strong> (IDT), to find the address of the exception handler. The IDT is a table of 256 entries, not all of which are used. Each entry contains the address of an interrupt handler, which is a function in the kernel that handles the interrupt. Intel reserves the first 32 entries for CPU exceptions, which is what we'll focus on in this section. The remaining entries are for hardware or software interrupts, which we'll cover in a later section.</p><h2 id="interrupt-descriptors" tabindex="-1"><a class="header-anchor" href="#interrupt-descriptors"><span>Interrupt Descriptors</span></a></h2><p>The IDT is an array of 256 entries, each is a 16-byte descriptor (in 64-bit mode). The index (not the offset) of a descriptor in the IDT is called an <strong>interrupt vector</strong>. Each descriptor points to an interrupt handler, which is a function in the kernel that handles that particular interrupt vector. During an interrupt, the interrupt vector is delivered to the CPU, which uses it as an index into the IDT to find the corresponding interrupt handler.</p><p>For example, the interrupt vector for a page fault is 14, so when a page fault occurs, the CPU will look at the 14th entry in the IDT to find the page fault handler. Another example is when a device is configured to use a particular interrupt vector, then when the device raises an interrupt, it places that vector on the bus, and the CPU will use it to find the interrupt handler in the IDT.</p><p>There are three types of descriptors in the IDT: task gates, interrupt gates, and trap gates. Task gates are used for hardware task switching, which is obsolete in 64-bit mode, so we'll focus only on interrupt gates and trap gates. The difference between the two is that interrupt gates disable interrupts when the handler is running, while trap gates do not.</p><p>Here's a diagram of interrupt/trap gate descriptors:</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line"> Interrupt/Trap Gate</span> 2<span class="line"> 31 00</span> 3<span class="line">âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ</span> 4<span class="line">â Reserved â 12</span> 5<span class="line">âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ</span> 6<span class="line"> 31 00</span> 7<span class="line">âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ</span> 8<span class="line">â Offset[63:32] â 8</span> 9<span class="line">âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ</span> 10<span class="line"> 31 16 15 14 13 12 11 08 07 04 03 02 00</span> 11<span class="line">âââââââââââââââââââââââââââââââââââââââââââââââââ¬âââ¬ââââââ¬âââ¬ââââââââââââ¬âââââââââ¬âââ¬âââ¬âââââââââ</span> 12<span class="line">â Offset[31:16] âP â DPL â 0â Type â0 0 0 â0 â0 â IST â 4</sp
12an> 13<span class="line">âââââââââââââââââââââââââââââââââââââââââââââââââ´âââ´ââââââ´âââ´ââââââââââââ´âââââââââ´âââ´âââ´âââââââââ</span> 14<span class="line"> 31 16 15 00</span> 15<span class="line">âââââââââââââââââââââââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââââââââââââââââââââ</span> 16<span class="line">â Segment Selector â Offset[15:00] â 0</span> 17<span class="line">âââââââââââââââââââââââââââââââââââââââââââââââââ´ââââââââââââââââââââââââââââââââââââââââââââââââ</span> 18<span class="line"></span> 19<span class="line">DPL Descriptor Privilege Level</span> 20<span class="line">Offset Offset to procedure entry point</span> 21<span class="line">P Segment Present flag</span> 22<span class="line">Selector Segment Selector for destination code segment</span> 23<span class="line">IST Interrupt Stack Table (index into IST in TSS)</span> 24<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></div><p>Some notes about the fields:</p><ul><li>The <strong>Segment Selector</strong> field is the segment selector for the destination code segment. Since all interrupt handlers are in the kernel, we'll set it to the kernel code segment selector.</li><li>The <strong>IST</strong> field has to do with stack switching during an interrupt, which we'll cover in a later section. For now, we'll set it to 0.</li><li>The <strong>Type</strong> field determines the type of interrupt gate. In 64-bit mode, there are two types of gates: interrupt gate (Type = <code>0b1110</code>) and trap gate (Type = <code>0b1111</code>).</li><li>The <strong>DPL</strong> field determines the privilege level required to invoke the interrupt handler. It'
24s checked only if an exception or interrupt is generated with an INT n, INT3, or INTO instruction. This is to prevent user programs from invoking privileged interrupt handlers, so we'll set it to 0.</li></ul><p>Let's create a new <code>idt.nim</code> module and define a type for interrupt gates. We'll also define a type for interrupt handlers, which is a procedure that takes a pointer to the interrupt stack frame as an argument.</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/kernel/idt.nim</span></span> 25<span class="line"><span class="token keyword">import</span> gdt</span> 26<span class="line"></span> 27<span class="line"><span class="token keyword">type</span></span> 28<span class="line"> InterruptGate <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 29<span class="line"> offset00<span class="token operator">:</span> uint16</span> 30<span class="line"> selector<span class="token operator">:</span> uint16 <span class="token operator">=</span> KernelCodeSegmentSelector</span> 31<span class="line"> ist <span class="token punctuation">{.</span>bitsize<span class="token operator">:</span> <span class="token number">3.</span><span class="token punctuation">}</span><span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">0</span></span> 32<span class="line"> zero0 <span class="token punctuation">{.</span>bitsize<span class="token operator">:</span> <span class="token number">5.</span><span class="token punctuation">}</span><span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">0</span></span> 33<span class="line"> <span class="token identifier"><span class="token punctuation">\`</span>type<span class="token punctuation">\`</span></span> <span class="token punctuation">{.</span>bitsize<span class="token operator">:</span> <span class="token number">4.</span><span class="token punctuation">}</span><span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">0b1110</span></span> 34<span class="line"> zero1 <span class="token punctuation">{.</span>bitsize<span class="token operator">:</span> <span class="token number">1.</span><span class="token punctuation">}</span><span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">0</span></span> 35<span class="line"> dpl <span class="token punctuation">{.</span>bitsize<span class="token operator">:</span> <span class="token number">2.</span><span class="token punctuation">}</span><span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">0</span></span> 36<span class="line"> present <span class="token punctuation">{.</span>bitsize<span class="token operator">:</span> <span class="token number">1.</span><span class="token punctuation">}</span><span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">1</span></span> 37<span class="line"> offset16<span class="token operator">:</span> uint16</span> 38<span class="line"> offset32<span class="token operator">:</span> uint32</span> 39<span class="line"> reserved<span class="token operator">:</span> uint32 <span class="token operator">=</span> <span class="token number">0</span></span> 40<span class="line"></span> 41<span class="line"> InterruptHandler <span class="token operator">=</span> <span class="token function">proc</span> <span class="token punctuation">(</span>frame<span class="token operator">:</span> pointer<span class="token punctuation">)</span> <span class="token punctuation">{.</span>cdecl<span class="token punctuation">.}</span></span> 42<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 also define a helper function to create a new interrupt gate given an interrupt handler.</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/kernel/idt.nim</span></span> 43<span class="line"></span> 44<span class="line"><span class="token keyword">proc</span> <span class="token function">newInterruptGate</span><span class="token punctuation">(</span>handler<span class="token operator">:</span> InterruptHandler<span class="token punctuation">)</span><span class="token operator">:</span> InterruptGate <span class="token operator">=</span></span> 45<span class="line"> <span class="token keyword">let</span> offset <span class="token operator">=</span> <span class="token function">cast[uint64]</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span></span> 46<span class="line"> result <span class="token operator">=</span> <span class="token function">InterruptGate</span><span class="token punctuation">(</span></span> 47<span class="line"> offset00<span class="token operator">:</span> <span class="token function">uint16</span><span class="token punctuation">(</span>offset<span class="token punctuation">)</span><span class="token punctuation">,</span></span> 48<span class="line"> offset16<span class="token operator">:</span> <span class="token function">uint16</span><span class="token punctuation">(</span>offset <span class="token operator">shr</span> <span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span> 49<span class="line"> offset32<span class="token operator">:</span> <span class="token function">uint32</span><span class="token punctuation">(</span>offset <span class="token operator">shr</span> <span class="token number">32</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span> 50<span class="line"> <span class="token punctuation">)</span></span> 51<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><p>
51Now we can create the IDT. We'll use a Nim array to represent the IDT. We'll also define a type for the IDT descriptor and declare a single instance of it, which we'll use to load the IDT into the IDTR register 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/kernel/idt.nim</span></span> 52<span class="line"><span class="token operator">...</span></span> 53<span class="line"></span> 54<span class="line"><span class="token keyword">type</span></span> 55<span class="line"> InterruptGate <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 56<span class="line"> <span class="token operator">...</span></span> 57<span class="line"></span> 58<span class="line highlighted"> IdtDescriptor <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span> 59<span class="line highlighted"> limit<span class="token operator">:</span> uint16</span> 60<span class="line highlighted"> base<span class="token operator">:</span> pointer</span> 61<span class="line highlighted"></span> 62<span class="line highlighted"><span class="token keyword">var</span></span> 63<span class="line highlighted"> idtEntries<span class="token operator">:</span> array<span class="token punctuation">[</span><span class="token number">256</span><span class="token punctuation">,</span> InterruptGate<span class="token punctuation">]</span></span> 64<span class="line highlighted"></span> 65<span class="line highlighted"><span class="token keyword">let</span></span> 66<span class="line highlighted"> idtDescriptor <span class="token operator">=</span> <span class="token function">IdtDescriptor</span><span class="token punctuation">(</span></span> 67<span class="line highlighted"> limit<span class="token operator">:</span> <span class="token function">sizeof</span><span class="token punctuation">(</span>idtEntries<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span></span> 68<span class="line highlighted"> base<span class="token operator">:</span> idtEntries<span class="token operator">.</span><span class="token keyword">addr</span></span> 69<span class="line highlighted"> <span class="token punctuation">)</span></span> 70<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></div><h2 id="defining-interrupt-handlers" tabindex="-1"><a class="header-anchor" href="#defining-interrupt-handlers"><span>Defining Interrupt Handlers</span></a></h2><p>Interrupt procedures are not normal procedures; there's a catch. When an interrupt handler is called, the CPU pushes some information onto the stack, called the <strong>interrupt stack frame</strong>. The handler must also return using the <code>iretq</code> instruction (as opposed to using <code>ret</code>), which pops the interrupt stack frame and returns to the interrupted program. Here's a diagram of the interrupt stack frame:</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line"> Handler's Stack</span> 71<span class="line"></span> 72<span class="line"> ââââââââââââââââââââ¤</span> 73<span class="line"> â â</span> 74<span class="line"> âââââââââââââââââââ⤠ââââ ââââ</span> 75<span class="line"> â SS â +40 â â</span> 76<span class="line"> âââââââââââââââââââ⤠â â</span> 77<span class="line"> â RSP â +32 â â</span> 78<span class="line"> âââââââââââââââââââ⤠â Stack â Stack</span> 79<span class="line"> â RFLAGS â +24 âââ Frame âââ Frame </span> 80<span class="line"> âââââââââââââââââââ⤠â (no error code) â (with error code)</span> 81<span class="line"> â CS â +16 â â</span> 82<span class="line"> âââââââââââââââââââ⤠â â</span> 83<span class="line"> â RIP â +8 â â</span> 84<span class="line"> âââââââââââââââââââ⤠ââââ â</span> 85<span class="line"> â Error Code â 0 â</span> 86<span class="line"> âââââââââââââââââââ⤠ââââ</span> 87<span class="line"> â â</span> 88<span class="line"> ââââââââââââââââââââ¤</span> 89<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></div><p>Notice that some CPU exceptions push an error code onto the stack. For others, the error code is not pushed. So we have to be careful when defining the different interrupt handlers.</p><p>Given this information, we can't just define a normal procedure as an interrupt handler; we have to tell the compiler to generate it differently. Fortunately, the C compiler has a special attribute called <code>interrupt</code> that can be used to define interrupt handlers. It generates appropriate function entry/exit code so that it can be used directly as an interrupt service routine. We can use the <code>codegenDecl</code> pragma to add this attribute to our interrupt handler signature.</p><p>Let's define a proof of concept interrupt handler that prints a debug message.</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/kernel/idt.nim</span></span> 90<span class="line"><span class="token operator">...</span></span> 91<span class="line"></span> 92<span class="line"><span class="token keyword">proc</span> <span class="token function">isr100</span><span class="token punctuation">(</span>frame<span class="token operator">:</span> pointer<span class="token punctuation">)</span> <span class="token punctuation">{.</span>cdecl<span class="token punctuation">,</span> codegenDecl<span class="token operator">:</span> <span class="token string">"__attribute__ ((interrupt)) $# $#$#"</span><span class="token punctuation">.}</span> <span class="token operator">=</span></span> 93<span class="line"> debugln <span class="token string">"Hello from isr100"</span></span> 94<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>Let's install this handler in the IDT. We'll use the <code>newInterruptGate</code> helper function we defined earlier to create a new interrupt gate, and then we'll assign it to the appropriate entry in the IDT. We'll also load the IDT into the IDTR register using the <code>
94lidt</code> instruction.</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/kernel/idt.nim</span></span> 95<span class="line"><span class="token operator">...</span></span> 96<span class="line"></span> 97<span class="line"><span class="token keyword">proc</span> <span class="token function">idtInit<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span></span> 98<span class="line"> idtEntries<span class="token punctuation">[</span><span class="token number">100</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">newInterruptGate</span><span class="token punctuation">(</span>isr100<span class="token punctuation">)</span></span> 99<span class="line"></span> 100<span class="line"> <span class="token keyword">asm</span> <span class="token string">"""</span> 101<span class="line"> lidt %0</span> 102<span class="line"> :</span> 103<span class="line"> : "m"(\`idtDescriptor\`)</span> 104<span class="line"> """</span></span> 105<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>I installed the handler at interrupt vector 100. This is just an arbitrary choice for testing. Let's now test it out by raising an interrupt using the <code>int</code> instruction.</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/kernel/main.nim</span></span> 106<span class="line"></span> 107<span class="line"><span class="token keyword">import</span> idt</span> 108<span class="line"><span class="token operator">...</span></span> 109<span class="line"></span> 110<span class="line"><span class="token keyword">proc</span> <span class="token function">KernelMainInner</span><span class="token punctuation">(</span>bootInfo<span class="token operator">:</span> <span class="token keyword">ptr</span> BootInfo<span class="token punctuation">)</span> <span class="token operator">=</span></span> 111<span class="line"> debugln <span class="token string">""</span></span> 112<span class="line"> debugln <span class="token string">"kernel: Fusion Kernel"</span></span> 113<span class="line"></span> 114<span class="line"> <span class="token operator">...</span></span> 115<span class="line"></span> 116<span class="line"> debug <span class="token string">"kernel: Initializing GDT "</span></span> 117<span class="line"> <span class="token function">gdtInit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 118<span class="line"> debugln <span class="token string">"[success]"</span></span> 119<span class="line"></span> 120<span class="line highlighted"> debug <span class="token string">"kernel: Initializing IDT "</span></span> 121<span class="line highlighted"> <span class="token function">idtInit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 122<span class="line highlighted"> debugln <span class="token string">"[success]"</span></span> 123<span class="line highlighted"></span> 124<span class="line highlighted"> debugln <span class="token string">"kernel: Invoking interrupt"</span></span> 125<span class="line highlighted"> <span class="token keyword">asm</span> <span class="token string">"int 100"</span></span> 126<span class="line highlighted"> debugln <span class="token string">"kernel: Returned from interrupt"</span></span> 127<span class="line"></span> 128<span class="line"> <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 129<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>If we run the kernel now, we should see the debug message printed to the terminal.</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">kernel: Fusion Kernel</span> 130<span class="line">...</span> 131<span class="line">kernel: Initializing IDT [success]</span> 132<span class="line">kernel: Invoking interrupt</span> 133<span class="line">Hello from isr100</span> 134<span class="line">kernel: Returned from interrupt</span> 135<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>Great! We have a working interrupt handler. Now we're ready to define interrupt handlers for CPU exceptions.</p><h2 id="handling-cpu-exceptions" tabindex="-1"><a class="header-anchor" href="#handling-cpu-exceptions"><span>Handling CPU Exceptions</span></a></h2><p>As mentioned earlier, Intel reserves the first 32 entries in the IDT for CPU exceptions. Not all 32 are used. Here's the list of CPU exceptions and interrupts as defined in the Intel manual:</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">ââââââââââ¬âââââââââââ¬ââââââââââââââââââââââââââ¬ââââââââââââ¬ââââââââ¬âââââââââââââââââââââââââââââââââââââ</span> 136<span class="line">â Vector â Mnemonic â Description â Type â Error â Source â</span> 137<span class="line">â â â â â Code â â</span> 138<span class="line">ââââââââââ¼âââââââââââ¼ââââââââââââââââââââââââââ¼ââââââââââââ¼ââââââââ¼âââââââââââââââââââââââââââââââââââââ¤</span> 139<span class="line">â 0 â #DE â Divide Error â Fault â No â DIV and IDIV instructions. â</span> 140<span class="line">â 1 â #DB â Debug Exception â Fault / â No â Instruction, data, and I/O â</span> 141<span class="line">â â â â Trap â â breakpoints; single-step; and â</span> 142<span class="line">â â â â â â others. â</span> 143<span class="line">â 2 â - â NMI Interrupt â Interrupt â No â Nonmaskable external interrupt. â</span> 144<span class="line">
144â 3 â #BP â Breakpoint â Trap â No â INT3 instruction. â</span> 145<span class="line">â 4 â #OF â Overflow â Trap â No â INTO instruction. â</span> 146<span class="line">â 5 â #BR â BOUND Range Exceeded â Fault â No â BOUND instruction. â</span> 147<span class="line">â 6 â #UD â Invalid Opcode â Fault â No â UD instruction or reserved opcode. â</span> 148<span class="line">â 7 â #NM â Device Not Available â Fault â No â Floating-point or WAIT/FWAIT â</span> 149<span class="line">â â â (No Math Coprocessor) â â â instruction. â</span> 150<span class="line">â 8 â #DF â Double Fault â Abort â Yes â Any instruction that can generate â</span> 151<span class="line">â â â â â (zero)â an exception, an NMI, or an INTR. â</span> 152<span class="line">â 9 â - â Coprocessor Segment â Fault â No â Floating-point instruction. â</span> 153<span class="line">â â â Overrun (reserved) â â â â</span> 154<span class="line">â 10 â #TS â Invalid TSS â Fault â Yes â Task switch or TSS access. â</span> 155<span class="line">â 11 â #NP â Segment Not Present â Fault â Yes â Loading segment registers or â</span> 156<span class="line">â â â â â â accessing system segments. â</span> 157<span class="line">â 12 â #SS â Stack-Segment Fault â Fault â Yes â Stack operations and
157SS register â</span> 158<span class="line">â â â â â â loads. â</span> 159<span class="line">â 13 â #GP â General Protection â Fault â Yes â Any memory reference and other â</span> 160<span class="line">â â â â â â protection checks. â</span> 161<span class="line">â 14 â #PF â Page Fault â Fault â Yes â Any memory reference. â</span> 162<span class="line">â 15 â - â (Intel reserved. Do not â - â No â - â</span> 163<span class="line">â â â use.) â â â â</span> 164<span class="line">â 16 â #MF â x87 FPU Floating-Point â Fault â No â x87 FPU floating-point or WAIT/ â</span> 165<span class="line">â â â Error (Math Fault) â â â FWAIT instruction. â</span> 166<span class="line">â 17 â #AC â Alignment Check â Fault â Yes â Any data reference in memory. â</span> 167<span class="line">â â â â â (zero)â â</span> 168<span class="line">â 18 â #MC â Machine Check â Abort â No â Error codes (if any) and source â</span> 169<span class="line">â â â â â â are model dependent. â</span> 170<span class="line">â 19 â #XM â SIMD Floating-Point â Fault â No â SSE/SSE2/SSE3 floating-point â</span> 171<span class="line">â â â Exception â â â instructions. â</span> 172<span class="line">â 20 â #VE â Virtualization Exceptionâ Fault â No â EPT violation â</span> 173<span class="line">â 21 â #CP â Control Protection â Fault â Yes â RET, IRET, RSTORSSP, and SETSSBSY â</span> 174<span class="line">â â â Exception â â â instructions. â</span> 175<span class="line">â 22-31 â - â Intel Reserved. Do not â - â - â - â</span> 176<span class="line">â â â use. â â â â</span> 177<span class="line">â 32-255 â - â User Defined â Interrupt â - â External interrupt or INT n â</span> 178<span class="line">â â â â â â instruction. â</span> 179<span class="line">ââââââââââ´âââââââââââ´ââââââââââââââââââââââââââ´ââââââââââââ´ââââââââ´âââââââââââââââââââââââââââââââââââââ</span> 180<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></div><p>The difference between <strong>Fault</strong> and <strong>Trap</strong> exceptions is that upon returning from a Fault, the CPU will re-execute the instruction that caused the fault (e.g. a page fault handler may allocate the missing page and then return to the instruction that caused the page fault, with no loss of continuity). On the other hand, upon returning from a Trap, the CPU will continue execution from the next instruction (e.g. a breakpoint trap handler may print a debug message and then return to the next instruction). <strong>Abort</strong> exceptions are not recoverable, and usually indicate severe errors, such as hardware errors.</p><p>Let's start by defining an exception handler for the divide error exception. Because this exception is a Fault, it will be retried indefinitely by the CPU. To avoid an infinite loop, we'll just print a debug message (and the stack trace) and then quit the kernel.</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/kernel/idt.nim</span></span> 181<span class="line"></span> 182<span class="line"><span class="token keyword">proc</span> <span class="token function">cpuDivideErrorHandler</span><span class="token punctuation">(</span>frame<span class="token operator">:</span> pointer<span class="token punctuation">)</span> <span class="token punctuation">{.</span>cdecl<span class="token punctuation">,</span> codegenDecl<span class="token operator">:</span> <span class="token string">"__attribute__ ((interrupt)) $# $#$#"</span><span class="token punctuation">.}</span> <span class="token operator">=</span></span> 183<span class="line"> debugln <span class="token string">"CPU Exception: Divide Error [#DE]"</span></span> 184<span class="line"> debugln <span class="token string">""</span></span> 185<span class="line"> debugln <span class="token function">getStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 186<span class="line"> <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 187<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>We'll also define a helper function to install the handler in the IDT.</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/kernel/idt.nim</span></span> 188<span class="line"></span> 189<span class="line"><span class="token keyword">proc</span> <span class="token function">installHandler</span><span class="token punctuation">(</span>vector<span class="token operator">:</span> uint8<span class="token punctuation">,</span> handler<span class="token operator">:</span> InterruptHandler<span class="token punctuation">)</span> <span class="token operator">=</span></span> 190<span class="line"> idtEntries<span class="token punctuation">[</span>vector<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">newInterruptGate</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span></span> 191<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>
191Now we can install the handler in the IDT.</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/kernel/idt.nim</span></span> 192<span class="line"></span> 193<span class="line"><span class="token keyword">proc</span> <span class="token function">idtInit<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span></span> 194<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> cpuDivideErrorHandler<span class="token punctuation">)</span></span> 195<span class="line"> <span class="token operator">...</span></span> 196<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>Let's try it out by raising a divide error exception.</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/kernel/main.nim</span></span> 197<span class="line"></span> 198<span class="line"><span class="token keyword">import</span> idt</span> 199<span class="line"></span> 200<span class="line"><span class="token keyword">proc</span> <span class="token function">KernelMainInner</span><span class="token punctuation">(</span>bootInfo<span class="token operator">:</span> <span class="token keyword">ptr</span> BootInfo<span class="token punctuation">)</span> <span class="token operator">=</span></span> 201<span class="line"> <span class="token operator">...</span></span> 202<span class="line"> debugln <span class="token string">"kernel: Invoking interrupt"</span></span> 203<span class="line highlighted"> <span class="token keyword">asm</span> <span class="token string">"""</span> 204<span class="line highlighted"> # Divide by zero</span> 205<span class="line highlighted"> xor rcx, rcx</span> 206<span class="line highlighted"> idiv rcx</span> 207<span class="line highlighted"> """</span></span> 208<span class="line"> debugln <span class="token string">"kernel: Returned from interrupt"</span></span> 209<span class="line"> <span class="token operator">...</span></span> 210<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></div><p>When we run the kernel, we should see the debug message and the stack trace printed to the terminal.</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">kernel: Fusion Kernel</span> 211<span class="line">...</span> 212<span class="line">kernel: Initializing IDT [success]</span> 213<span class="line">kernel: Invoking interrupt</span> 214<span class="line"></span> 215<span class="line">CPU Exception: Divide Error</span> 216<span class="line"></span> 217<span class="line">Traceback (most recent call last)</span> 218<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(58) KernelMain</span> 219<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(87) KernelMainInner</span> 220<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/idt.nim(68) cpuDivideErrorHandler</span> 221<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>Great! Our exception handler is working, and we can see the stack trace (since the interrupt is using the same stack). Now we can define handlers for the remaining CPU exceptions. But it would be tedious to write almost the same code for each handler. So let's use a Nim template to generate the handlers for us.</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/kernel/idt.nim</span></span> 222<span class="line"></span> 223<span class="line"><span class="token keyword">template</span> <span class="token function">createHandler<span class="token operator">*</span></span><span class="token punctuation">(</span>name<span class="token operator">:</span> untyped<span class="token punctuation">,</span> msg<span class="token operator">:</span> string<span class="token punctuation">)</span> <span class="token operator">=</span></span> 224<span class="line"> <span class="token keyword">proc</span> <span class="token function">name<span class="token operator">*</span></span><span class="token punctuation">(</span>frame<span class="token operator">:</span> pointer<span class="token punctuation">)</span> <span class="token punctuation">{.</span>cdecl<span class="token punctuation">,</span> codegenDecl<span class="token operator">:</span> <span class="token string">"__attribute__ ((interrupt)) $# $#$#"</span><span class="token punctuation">.}</span> <span class="token operator">=</span></span> 225<span class="line"> debugln <span class="token string">"CPU Exception: "</span><span class="token punctuation">,</span>
225 msg</span> 226<span class="line"> debugln <span class="token string">""</span></span> 227<span class="line"> debugln <span class="token function">getStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 228<span class="line"> <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 229<span class="line"></span> 230<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuDivideErrorHandler<span class="token punctuation">,</span> <span class="token string">"Divide Error"</span><span class="token punctuation">)</span></span> 231<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuDebugErrorHandler<span class="token punctuation">,</span> <span class="token string">"Debug Exception"</span><span class="token punctuation">)</span></span> 232<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuNmiInterruptHandler<span class="token punctuation">,</span> <span class="token string">"NMI Interrupt"</span><span class="token punctuation">)</span></span> 233<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuBreakpointHandler<span class="token punctuation">,</span> <span class="token string">"Breakpoint"</span><span class="token punctuation">)</span></span> 234<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuOverflowHandler<span class="token punctuation">,</span> <span class="token string">"Overflow"</span><span class="token punctuation">)</span></span> 235<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuBoundRangeExceededHandler<span class="token punctuation">,</span> <span class="token string">"Bound Range Exceeded"</span><span class="token punctuation">)</span></span> 236<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuInvalidOpcodeHandler<span class="token punctuation">,</span> <span class="token string">"Invalid Opcode"</span><span class="token punctuation">)</span></span> 237<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuDeviceNotAvailableHandler<span class="token punctuation">,</span> <span class="token string">"Device Not Available"</span><span class="token punctuation">)</span></span> 238<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuDoubleFaultHandler<span class="token punctuation">,</span> <span class="token string">"Double Fault"</span><span class="token punctuation">)</span></span> 239<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuCoprocessorSegmentOverrunHandler<span class="token punctuation">,</span> <span class="token string">"Coprocessor Segment Overrun"</span><span class="token punctuation">)</span></span> 240<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuInvalidTssHandler<span class="token punctuation">,</span> <span class="token string">"Invalid TSS"</span><span class="token punctuation">)</span></span> 241<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuSegmentNotPresentHandler<span class="token punctuation">,</span> <span class="token string">"Segment Not Present"</span><span class="token punctuation">)</span></span> 242<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuStackSegmentFaultHandler<span class="token punctuation">,</span> <span class="token string">"Stack Segment Fault"</span><span class="token punctuation">)</span></span> 243<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuGeneralProtectionFaultHandler<span class="token punctuation">,</span> <span class="token string">"General Protection Fault"</span><span class="token punctuation">)</span></span> 244<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuPageFaultHandler<span class="token punctuation">,</span> <span class="token string">"Page Fault"</span><span class="token punctuation">)</span></span> 245<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuX87FloatingPointErrorHandler<span class="token punctuation">,</span> <span class="token string">"x87 Floating Point Error"</span><span class="token punctuation">)</span></span> 246<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuAlignmentCheckHandler<span class="token punctuation">,</span> <span class="token string">"Alignment Check"</span><span class="token punctuation">)</span></span> 247<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuMachineCheckHandler<span class="token punctuation">,</span> <span class="token string">"Machine Check"</span><span class="token punctuation">)</span></span> 248<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuSimdFloatingPointExceptionHandler<span class="token punctuation">,</span> <span class="token string">"SIMD Floating Point Exception"</span><span class="token punctuation">)</span></span> 249<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuVirtualizationExceptionHandler<span class="token punctuation">,</span> <span class="token string">"Virtualization Exception"</span><span class="token punctuation">)</span></span> 250<span class="line"><span class="token function">createHandler</span><span class="token punctuation">(</span>cpuControlProtectionExceptionHandler<span class="token punctuation">,</span> <span class="token string">"Control Protection Exception"</span><span class="token punctuation">)</span></span> 251<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></div><p>
251Now we can install the handlers in the IDT.</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/kernel/idt.nim</span></span> 252<span class="line"><span class="token operator">...</span></span> 253<span class="line"></span> 254<span class="line"><span class="token keyword">proc</span> <span class="token function">idtInit<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span></span> 255<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> cpuDivideErrorHandler<span class="token punctuation">)</span></span> 256<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> cpuDebugErrorHandler<span class="token punctuation">)</span></span> 257<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> cpuNmiInterruptHandler<span class="token punctuation">)</span></span> 258<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> cpuBreakpointHandler<span class="token punctuation">)</span></span> 259<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">,</span> cpuOverflowHandler<span class="token punctuation">)</span></span> 260<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> cpuBoundRangeExceededHandler<span class="token punctuation">)</span></span> 261<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">,</span> cpuInvalidOpcodeHandler<span class="token punctuation">)</span></span> 262<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">7</span><span class="token punctuation">,</span> cpuDeviceNotAvailableHandler<span class="token punctuation">)</span></span> 263<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">,</span> cpuDoubleFaultHandler<span class="token punctuation">)</span></span> 264<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">9</span><span class="token punctuation">,</span> cpuCoprocessorSegmentOverrunHandler<span class="token punctuation">)</span></span> 265<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">,</span> cpuInvalidTssHandler<span class="token punctuation">)</span></span> 266<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">11</span><span class="token punctuation">,</span> cpuSegmentNotPresentHandler<span class="token punctuation">)</span></span> 267<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">12</span><span class="token punctuation">,</span> cpuStackSegmentFaultHandler<span class="token punctuation">)</span></span> 268<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">,</span> cpuGeneralProtectionFaultHandler<span class="token punctuation">)</span></span> 269<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">14</span><span class="token punctuation">,</span> cpuPageFaultHandler<span class="token punctuation">)</span></span> 270<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">,</span> cpuX87FloatingPointErrorHandler<span class="token punctuation">)</span></span> 271<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">17</span><span class="token punctuation">,</span> cpuAlignmentCheckHandler<span class="token punctuation">)</span></span> 272<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">18</span><span class="token punctuation">,</span> cpuMachineCheckHandler<span class="token punctuation">)</span></span> 273<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">19</span><span class="token punctuation">,</span> cpuSimdFloatingPointExceptionHandler<span class="token punctuation">)</span></span> 274<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">,</span> cpuVirtualizationExceptionHandler<span class="token punctuation">)</span></span> 275<span class="line highlighted"> <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">21</span><span class="token punctuation">,</span> cpuControlProtectionExceptionHandler<span class="token punctuation">)</span></span> 276<span class="line"></span> 277<span class="line"> <span class="token keyword">asm</span> <span class="token string">"""</span> 278<span class="line"> lidt %0</span> 279<span class="line"> :</span> 280<span class="line"> : "m"(\`idtDescriptor\`)</span> 281<span class="line"> """</span></span> 282<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></div><h2 id="page-fault-handler" tabindex="-1"><a class="header-anchor" href="#page-fault-handler"><span>Page Fault Handler</span></a></h2><p>One particular interrupt handler that we need to customize a bit is the <strong>Page Fault</strong> handler. When this exception is raised, the CPU stores the address that caused the page fault in the <code>CR2</code> register. At some point we'll use this address to allocate a new page and map it to the address that caused the page fault. But for now, let's just print the address and quit.</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/kernel/idt.nim</span></span> 283<span class="line"></span> 284<span class="line"><span class="token comment"># remove this line from before:</span></span> 285<span class="line"><span class="token comment"># createHandler(cpuPageFaultHandler, "Page Fault")</span></span> 286<span class="line"></span> 287<span class="line"><span class="token keyword">proc</span> <span class="token function">cpuPageFaultHandler<span class="token operator">*</span></span><span class="token punctuation">(</span>frame<span class="token operator">:</span> pointer<span class="token punctuation">)</span> <span class="token punctuation">{.</span>cdecl<span class="token punctuation">,</span> codegenDecl<span class="token operator">:</span> <span class="token string">"__attribute__ ((interrupt)) $# $#$#"</span><span class="token punctuation">.}</span> <span class="token operator">=</span></span> 288<span class="line"> debugln <span class="token string">""</span></span> 289<span class="line"> debugln <span class="token string">"CPU Exception: Page Fault"</span></span> 290<span class="line"> <span class="token comment"># get the faulting address</span></span> 291<span class="line"> <span class="token keyword">var</span> cr2<span class="token operator">:</span> uint64</span> 292<span class="line"> <span class="token keyword">asm</span> <span class="token string">"""</span> 293<span class="line">
293 mov %0, cr2</span> 294<span class="line"> : "=r"(\`cr2\`)</span> 295<span class="line"> """</span></span> 296<span class="line"> debugln <span class="token operator">&</span><span class="token string">" Faulting address: {cr2:#018x}"</span></span> 297<span class="line"> debugln <span class="token string">""</span></span> 298<span class="line"> debugln <span class="token function">getStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 299<span class="line"> <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span> 300<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 try it out by raising a page fault exception.</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/kernel/main.nim</span></span> 301<span class="line"></span> 302<span class="line"><span class="token keyword">import</span> idt</span> 303<span class="line"></span> 304<span class="line"><span class="token keyword">proc</span> <span class="token function">KernelMainInner</span><span class="token punctuation">(</span><span class="token operator">..</span><span class="token punctuation">.)</span> <span class="token operator">=</span></span> 305<span class="line"> <span class="token operator">...</span></span> 306<span class="line"> debugln <span class="token string">"kernel: Invoking interrupt"</span></span> 307<span class="line highlighted"> <span class="token keyword">let</span> p <span class="token operator">=</span> <span class="token function">cast[ptr uint8]</span><span class="token punctuation">(</span><span class="token number">0xdeadbeef</span><span class="token punctuation">)</span></span> 308<span class="line highlighted"> <span class="token keyword">let</span> x <span class="token operator">=</span> p<span class="token punctuation">[</span><span class="token punctuation">]</span></span> 309<span class="line"> debugln <span class="token string">"kernel: Returned from interrupt"</span></span> 310<span class="line"> <span class="token operator">...</span></span> 311<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>And when we run the kernel, we should see the page fault error message.</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">kernel: Fusion Kernel</span> 312<span class="line">kernel: Initializing IDT [success]</span> 313<span class="line">kernel: Invoking interrupt</span> 314<span class="line"></span> 315<span class="line">CPU Exception: Page Fault</span> 316<span class="line"> Faulting address: 0x00000000deadbeef</span> 317<span class="line"></span> 318<span class="line">Traceback (most recent call last)</span> 319<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(58) KernelMain</span> 320<span class="line">
320/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(88) KernelMainInner</span> 321<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/idt.nim(57) cpuPageFaultHandler</span> 322<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>Beautiful! The handler is working, and we know which address caused the page fault. One thing we can test also is double faults. We can try this by commenting out the installation of the page fault handler, and then causing a page fault. The CPU will then raise a double fault exception, because it can't find an interrupt handler during another exception (the page fault).</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/kernel/idt.nim</span></span> 323<span class="line"></span> 324<span class="line"><span class="token keyword">proc</span> <span class="token function">idtInit<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span></span> 325<span class="line"> <span class="token operator">...</span></span> 326<span class="line"> <span class="token comment"># installHandler(14, cpuPageFaultHandler)</span></span> 327<span class="line"> <span class="token operator">...</span></span> 328<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>If we run the kernel now, we should see the double fault error message.</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">kernel: Fusion Kernel</span> 329<span class="line">...</span> 330<span class="line">kernel: Initializing IDT [success]</span> 331<span class="line">kernel: Invoking interrupt</span> 332<span class="line"></span> 333<span class="line">CPU Exception: Double Fault</span> 334<span class="line"></span> 335<span class="line">Traceback (most recent call last)</span> 336<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(58) KernelMain</span> 337<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(88) KernelMainInner</span> 338<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/idt.nim(65) cpuDoubleFaultHandler</span> 339<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>Amazing! We now have a safety net for CPU exceptions. If we mess up something in the kernel, we should get a debug message instead of a random hang or reboot. We will come back to properly implement some of these handlers later, especially the page fault handler.</p><p>Let's now turn our attention to user mode. In the next section, we'll see how we can switch to user mode, while still allowing interrupts to occur.</p>`,61)]))}const r=s(i,[["render",l],["__file","15-interrupts.html.vue"]]),o=JSON.parse(`{"path":"/osdev/15-interrupts.html","title":"Interrupts","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Interrupt Descriptors","slug":"interrupt-descriptors","link":"#interrupt-descriptors","children":[]},{"level":2,"title":"Defining Interrupt Handlers","slug":"defining-interrupt-handlers","link":"#defining-interrupt-handlers","children":[]},{"level":2,"title":"Handling CPU Exceptions","slug":"handling-cpu-exceptions","link":"#handling-cpu-exceptions","children":[]},{"level":2,"title":"Page Fault Handler","slug":"page-fault-handler","link":"#page-fault-handler","children":[]}
339],"git":{"updatedTime":1744638230000},"filePathRelative":"osdev/15-interrupts.md","excerpt":"\\n<p>When the CPU encounters an error, e.g. a division by zero or a page fault, it will raise\\nan exception, which is a kind of interrupt. The CPU consults a table, called the\\n<strong>Interrupt Descriptor Table</strong> (IDT), to find the address of the exception handler. The\\nIDT is a table of 256 entries, not all of which are used. Each entry contains the address\\nof an interrupt handler, which is a function in the kernel that handles the interrupt.\\nIntel reserves the first 32 entries for CPU exceptions, which is what we'll focus on in\\nthis section. The remaining entries are for hardware or software interrupts, which we'll\\ncover in a later section.</p>"}`);export{r as comp,o 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.