PageSourceSearch

https://0xc0ffee.netlify.app/assets/17-tss.html-6UGcg5Fv.js

js 0xc0ffee.netlify.app collected 2026-10-03 10:23:41 UTC 57,174 bytes, 272 lines download raw bytes

1import{_ as n,c as a,e,o as t}from"./app-CjUkjRdW.js";const p={};function i(l,s){return t(),a("div",null,s[0]||(s[0]=[e(`<h1 id="task-state-segment" tabindex="-1"><a class="header-anchor" href="#task-state-segment"><span>Task State Segment</span></a></h1><p>While running in user mode, an interrupt/exception or a system call causes the CPU to switch to kernel mode. This causes a change in privilege level (from CPL=3 to CPL=0). The CPU cannot use the user stack while in kernel mode, since the interrupt could have been caused by something that makes the stack unusable, e.g. a page fault caused by running out of stack space. So, the CPU needs to switch to a known good stack. This is where the Task State Segment (TSS) comes in.</p><p>The TSS originally was designed to support hardware task switching. This is a feature that allows the CPU to switch between multiple tasks (each having its own TSS) without software intervention. This feature is not used in modern operating systems, which rely on software task switching, but the TSS is still used to switch stacks when entering kernel mode.</p><p>The TSS on x64 contains two sets of stack pointers:</p><ul><li>One set holds three stack pointers, <code>RSP0</code>, <code>RSP1</code>, and <code>RSP2</code>, to use when switching to CPL=0, CPL=1, and CPL=2, respectively. Typically, only <code>RSP0</code> is used when switching from user mode to kernel mode, since rings 1 and 2 are not used in modern operating systems.</li><li>The other set holds the so-called Interrupt Stack Table, which can hold up to seven stack pointers, <code>IST1</code> through <code>IST7</code>, to use when handling interrupts. The decision to use one of those stacks is made by the Interrupt Descriptor Table entry for the interrupt. The stack pointer to use is stored in the <code>IST</code> field of the IDT entry. This means that different interrupts can use different stacks. If an IDT entry doesn&#39;t specify a stack, the CPU uses the stack pointed to by <code>RSP0</code>.</li></ul><p>Here&#39;s a diagram of the TSS structure:</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">                 64-bit TSS Structure</span>
2<span class="line">   31                                              00</span>
3<span class="line">  ┌────────────────────────┬────────────────────────┐</span>
4<span class="line">  │ I/O Map Base Address   │        Reserved        │ 100</span>
5<span class="line">  ├────────────────────────┴────────────────────────┤</span>
6<span class="line">  │                  Reserved                       │ 96</span>
7<span class="line">  ├─────────────────────────────────────────────────┤</span>
8<span class="line">  │                  Reserved                       │ 92</span>
9<span class="line">  ├─────────────────────────────────────────────────┤</span>
10<span class="line">  │                  IST7 (hi)                      │ 88</span>
11<span class="line">  ├─────────────────────────────────────────────────┤</span>
12<span class="line">  │                  IST7 (lo)                      │ 84</span>
13<span class="line">  ├─────────────────────────────────────────────────┤</span>
14<span class="line">  │                     ...                         │</span>
15<span class="line">  ├─────────────────────────────────────────────────┤</span>
16<span class="line">  │                  IST1 (hi)                      │ 40</span>
17<span class="line">  ├─────────────────────────────────────────────────┤</span>
18<span class="line">  │                  IST1 (lo)                      │ 36</span>
19<span class="line">  ├─────────────────────────────────────────────────┤</span>
20<span class="line">  │                  Reserved                       │ 32</span>
21<span class="line">  ├─────────────────────────────────────────────────┤</span>
22<span class="line">  │                  Reserved                       │ 28</span>
23<span class="line">  ├─────────────────────────────────────────────────┤</span>
24<span class="line">  │                  RSP2 (hi)                      │ 24</span>
25<span class="line">  ├─────────────────────────────────────────────────┤</span>
26<span class="line">  │                  RSP2 (lo)                      │ 20</span>
27<span class="line">  ├─────────────────────────────────────────────────┤</span>
28<span class="line">  │                  RSP1 (hi)                      │ 16</span>
29<span class="line">  ├─────────────────────────────────────────────────┤</span>
30<span class="line">  │                  RSP1 (lo)                      │ 12</span>
31<span class="line">  ├─────────────────────────────────────────────────┤</span>
32<span class="line">  │                  RSP0 (hi)                      │ 8</span>
33<span class="line">  ├─────────────────────────────────────────────────┤</span>
34<span class="line">
34  │                  RSP0 (lo)                      │ 4</span>
35<span class="line">  ├─────────────────────────────────────────────────┤</span>
36<span class="line">  │                  Reserved                       │ 0</span>
37<span class="line">  └─────────────────────────────────────────────────┘</span>
38<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></div><p>So, how does the CPU find the TSS? There&#39;s a special register called <code>TR</code> (Task Register) that holds the segment selector of the TSS. The CPU uses this selector to find the TSS in the GDT. So, what we need to do is to create a TSS and load its selector into <code>TR</code>.</p><h2 id="creating-a-tss" tabindex="-1"><a class="header-anchor" href="#creating-a-tss"><span>Creating a TSS</span></a></h2><p>Let&#39;s define the TSS structure in <code>src/kernel/gdt.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/kernel/gdt.nim</span></span>
39<span class="line"></span>
40<span class="line"><span class="token keyword">type</span></span>
41<span class="line">  TaskStateSegment <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span>
42<span class="line">    reserved0<span class="token operator">:</span> uint32</span>
43<span class="line">    rsp0<span class="token operator">:</span> uint64</span>
44<span class="line">    rsp1<span class="token operator">:</span> uint64</span>
45<span class="line">    rsp2<span class="token operator">:</span> uint64</span>
46<span class="line">    reserved1<span class="token operator">:</span> uint64</span>
47<span class="line">    ist1<span class="token operator">:</span> uint64</span>
48<span class="line">    ist2<span class="token operator">:</span> uint64</span>
49<span class="line">    ist3<span class="token operator">:</span> uint64</span>
50<span class="line">    ist4<span class="token operator">:</span> uint64</span>
51<span class="line">    ist5<span class="token operator">:</span> uint64</span>
52<span class="line">    ist6<span class="token operator">:</span> uint64</span>
53<span class="line">    ist7<span class="token operator">:</span> uint64</span>
54<span class="line">    reserved2<span class="token operator">:</span> uint64</span>
55<span class="line">    reserved3<span class="token operator">:</span> uint16</span>
56<span class="line">    iomapBase<span class="token operator">:</span> uint16</span>
57<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>We&#39;ll need to define a new descriptor type for the TSS, so that we can add it to the GDT. This will be a system descriptor (
57as opposed to a code or data descriptor).</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/gdt.nim</span></span>
58<span class="line"></span>
59<span class="line"><span class="token keyword">type</span></span>
60<span class="line">  TaskStateSegmentDescriptor <span class="token punctuation">{.</span>packed<span class="token punctuation">.}</span> <span class="token operator">=</span> <span class="token keyword">object</span></span>
61<span class="line">    limit00<span class="token operator">:</span> uint16</span>
62<span class="line">    base00<span class="token operator">:</span> uint16</span>
63<span class="line">    base16<span class="token operator">:</span> uint8</span>
64<span class="line">    <span class="token identifier"><span class="token punctuation">\`</span>type<span class="token punctuation">\`</span></span><span class="token operator">*</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">0b1001</span>  <span class="token comment"># 64-bit TSS</span></span>
65<span class="line">    s <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 class="token comment"># System segment</span></span>
66<span class="line">    dpl<span class="token operator">*</span> <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>
67<span class="line">    p<span class="token operator">*</span> <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>
68<span class="line">    limit16 <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>
69<span class="line">    avl<span class="token operator">*</span> <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>
70<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>
71<span class="line">    zero2 <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>
72<span class="line">    g <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>
73<span class="line">    base24<span class="token operator">:</span> uint8</span>
74<span class="line">    base32<span class="token operator">:</span> uint32</span>
75<span class="line">    reserved1<span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">0</span></span>
76<span class="line">    zero3 <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>
77<span class="line">    reserved2 <span class="token punctuation">{.</span>bitsize<span class="token operator">:</span> <span class="token number">19.</span><span class="token punctuation">}</span><span class="token operator">:</span> uint32 <span class="token operator">=</span> <span class="token number">0</span></span>
78<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Now, let&#39;s create an instance of the TSS and a descriptor for it. Later, we&#39;ll create a kernel stack and set <code>RSP0</code> to point to it.</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/gdt.nim</span></span>
79<span class="line"></span>
80<span class="line"><span class="token keyword">var</span></span>
81<span class="line">  tss<span class="token operator">*</span> <span class="token operator">=</span> <span class="token function">TaskStateSegment</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
82<span class="line"></span>
83<span class="line"><span class="token keyword">let</span></span>
84<span class="line">  tssDescriptor <span class="token operator">=</span> <span class="token function">TaskStateSegmentDescriptor</span><span class="token punctuation">(</span></span>
85<span class="line">    dpl<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span></span>
86<span class="line">    base00<span class="token operator">:</span> <span class="token function">cast[uint16]</span><span class="token punctuation">(</span>tss<span class="token operator">.</span><span class="token keyword">addr</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
87<span class="line">    base16<span class="token operator">:</span> <span class="token function">cast[uint8]</span><span class="token punctuation">(</span><span class="token function">cast[uint64]</span><span class="token punctuation">(</span>tss<span class="token operator">.</span><span class="token keyword">addr</span><span class="token punctuation">)</span> <span class="token operator">shr</span> <span class="token number">16</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
88<span class="line">    base24<span class="token operator">:</span> <span class="token function">cast[uint8]</span><span class="token punctuation">(</span><span class="token function">cast[uint64]</span><span class="token punctuation">(</span>tss<span class="token operator">.</span><span class="token keyword">addr</span><span class="token punctuation">)</span> <span class="token operator">shr</span> <span class="token number">24</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
89<span class="line">    base32<span class="token operator">:</span> <span class="token function">cast[uint32]</span><span class="token punctuation">(</span><span class="token function">cast[uint64]</span><span class="token punctuation">(</span>tss<span class="token operator">.</span><span class="token keyword">addr</span><span class="token punctuation">)</span> <span class="token operator">shr</span> <span class="token number">32</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
90<span class="line">    limit00<span class="token operator">:</span> <span class="token function">cast[uint16]</span><span class="token punctuation">(</span><span class="token function">sizeof</span><span class="token punctuation">(</span>tss<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span></span>
91<span class="line">    limit16<span class="token operator">:</span> <span class="token function">cast[uint8]</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token function">sizeof</span><span class="token punctuation">(</span>tss<span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">shr</span> <span class="token number">16</span><span class="token punctuation">)</span></span>
92<span class="line">  <span class="token punctuation">)</span></span>
93<span class="line">  tssDescriptorLo <span class="token operator">=</span> <span class="token function">cast[uint64]</span><span class="token punctuation">(</span>tssDescriptor<span class="token punctuation">)</span></span>
94<span class="line">  tssDescriptorHi <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token function">cast[ptr uint64]</span><span class="token punctuation">(</span><span class="token function">cast[uint64]</span><span class="token punctuation">(</span>tssDescriptor<span class="token operator">.</span><span class="token keyword">addr</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">)</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 class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="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>Finally, let&#39;s add the descriptor to the GDT and define its selector. Notice that the GDT entry occupies two 64-bit slots (since the TSS descriptor is 128 bits long). The selector points to the first slot (the low 64 bits).</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/gdt.nim</span></span>
96<span class="line"><span class="token operator">...</span></span>
97<span class="line"></span>
98<span class="line"><span class="token keyword">const</span></span>
99<span class="line">  KernelCodeSegmentSelector<span class="token operator">*</span> <span class="token operator">=</span> <span class="token number">0x08</span></span>
100<span class="line">  DataSegmentSelector<span class="token operator">*</span>
100       <span class="token operator">=</span> <span class="token number">0x10</span> <span class="token operator">or</span> <span class="token number">3</span> <span class="token comment"># RPL = 3</span></span>
101<span class="line">  UserCodeSegmentSelector<span class="token operator">*</span>   <span class="token operator">=</span> <span class="token number">0x18</span> <span class="token operator">or</span> <span class="token number">3</span> <span class="token comment"># RPL = 3</span></span>
102<span class="line highlighted">  TaskStateSegmentSelector<span class="token operator">*</span>  <span class="token operator">=</span> <span class="token number">0x20</span></span>
103<span class="line"></span>
104<span class="line"><span class="token keyword">let</span></span>
105<span class="line">  <span class="token operator">...</span></span>
106<span class="line"></span>
107<span class="line">  gdtEntries <span class="token operator">=</span> <span class="token punctuation">[</span></span>
108<span class="line">    NullSegmentDescriptor<span class="token operator">.</span>value<span class="token punctuation">,</span></span>
109<span class="line">    <span class="token function">CodeSegmentDescriptor</span><span class="token punctuation">(</span>dpl<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">.</span>value<span class="token punctuation">,</span> <span class="token comment"># Kernel code segment</span></span>
110<span class="line">    <span class="token function">DataSegmentDescriptor</span><span class="token punctuation">(</span>dpl<span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token operator">.</span>value<span class="token punctuation">,</span> <span class="token comment"># Data segment (shared)</span></span>
111<span class="line">    <span class="token function">CodeSegmentDescriptor</span><span class="token punctuation">(</span>dpl<span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token operator">.</span>value<span class="token punctuation">,</span> <span class="token comment"># User code segment</span></span>
112<span class="line highlighted">    tssDescriptorLo<span class="token punctuation">,</span>                     <span class="token comment"># Task state segment (low 64 bits)</span></span>
113<span class="line highlighted">    tssDescriptorHi<span class="token punctuation">,</span>                     <span class="token comment"># Task state segment (high 64 bits)</span></span>
114<span class="line">  <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><h2 id="loading-the-tss" tabindex="-1"><a class="header-anchor" href="#loading-the-tss"><span>Loading the TSS</span></a></h2><p>To tell the CPU to use the TSS, we need to load its selector into <code>TR</code> (Task Register). We&#39;ll do this as part of the <code>gdtInit</code> proc.</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/gdt.nim</span></span>
116<span class="line"><span class="token operator">...</span></span>
117<span class="line"></span>
118<span class="line"><span class="token keyword">proc</span> <span class="token function">gdtInit<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{.</span>asmNoStackFrame<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
119<span class="line">  <span class="token operator">...</span></span>
120<span class="line">  <span class="token keyword">asm</span> <span class="token string">&quot;&quot;&quot;</span>
121<span class="line">    lgdt %0</span>
122<span class="line"></span>
123<span class="line highlighted">
123    mov ax, %3</span>
124<span class="line highlighted">    ltr ax</span>
125<span class="line"></span>
126<span class="line">    # reload CS using a far return</span>
127<span class="line">    ...</span>
128<span class="line"></span>
129<span class="line">    :</span>
130<span class="line">    : &quot;m&quot;(\`gdtDescriptor\`),</span>
131<span class="line">      &quot;i&quot;(\`KernelCodeSegmentSelector\`),</span>
132<span class="line">      &quot;i&quot;(\`DataSegmentSelector\`),</span>
133<span class="line highlighted">      &quot;i&quot;(\`TaskStateSegmentSelector\`)</span>
134<span class="line">    : &quot;rax&quot; </span>
135<span class="line">  &quot;&quot;&quot;</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 class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="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="kernel-switch-stack" tabindex="-1"><a class="header-anchor" href="#kernel-switch-stack"><span>Kernel Switch Stack</span></a></h2><p>We now need to define a new stack to use when switching to kernel mode. Let&#39;s allocate a page for it, map it, and set the <code>RSP0</code> field of the TSS to point to it.</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>
137<span class="line"><span class="token operator">...</span></span>
138<span class="line"></span>
139<span class="line"><span class="token keyword">proc</span> <span class="token function">KernelMain</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 punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
140<span class="line">  <span class="token operator">...</span></span>
141<span class="line"></span>
142<span class="line">  <span class="token comment"># allocate and map user stack</span></span>
143<span class="line">  <span class="token operator">...</span></span>
144<span class="line"></span>
145<span class="line highlighted">  <span class="token comment"># create a kernel switch stack and set tss.rsp0</span></span>
146<span class="line highlighted">  debugln <span class="token string">&quot;kernel: Creating kernel switch stack&quot;</span></span>
147<span class="line highlighted">  <span class="token keyword">let</span> switchStackPhysAddr <span class="token operator">=</span> <span class="token function">pmAlloc</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token operator">.</span>get</span>
148<span class="line highlighted">  <span class="token keyword">let</span> switchStackVirtAddr <span class="token operator">=</span> <span class="token function">p2v</span><span class="token punctuation">(</span>switchStackPhysAddr<span class="token punctuation">)</span></span>
149<span class="line highlighted">  <span class="token function">mapRegion</span><span class="token punctuation">(</span></span>
150<span class="line highlighted">    pml4 <span class="token operator">=</span> kpml4<span class="token punctuation">,</span></span>
151<span class="line highlighted">    virtAddr <span class="token operator">=</span> switchStackVirtAddr<span class="token punctuation">,</span></span>
152<span class="line highlighted">    physAddr <span class="token operator">=</span> switchStackPhysAddr<span class="token punctuation">,</span></span>
153<span class="line highlighted">    pageCount <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">,</span></span>
154<span class="line highlighted">    pageAccess <span class="token operator">=</span> paReadWrite<span class="token punctuation">,</span></span>
155<span class="line highlighted">    pageMode <span class="token operator">=</span> pmSupervisor<span class="token punctuation">,</span></span>
156<span class="line highlighted">  <span class="token punctuation">)</span></span>
157<span class="line highlighted">  tss<span class="token operator">.</span>rsp0 <span class="token operator">=</span> <span class="token function">uint64</span><span class="token punctuation">(</span>
157switchStackVirtAddr <span class="token operator">+!</span> PageSize<span class="token punctuation">)</span></span>
158<span class="line"></span>
159<span class="line">  <span class="token comment"># create interrupt stack frame</span></span>
160<span class="line">  <span class="token operator">...</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>Everything is now ready for the switch to kernel mode. There are a few ways to try this out.</p><h2 id="switching-to-kernel-mode" tabindex="-1"><a class="header-anchor" href="#switching-to-kernel-mode"><span>Switching to Kernel Mode</span></a></h2><p>One way to test this is to have the user task try to execute a privileged instruction, such as <code>hlt</code>. This should cause a General Protection Fault exception, which will trigger the switch to kernel mode. Let&#39;s try this out.</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/user/utask.nim</span></span>
162<span class="line"><span class="token operator">...</span></span>
163<span class="line"></span>
164<span class="line"><span class="token keyword">proc</span> <span class="token function">UserMain<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
165<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
166<span class="line"></span>
167<span class="line">  <span class="token keyword">asm</span> <span class="token string">&quot;hlt&quot;</span></span>
168<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>Let&#39;s run and see what happens.</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>
169<span class="line">...</span>
170<span class="line">kernel: Creating kernel switch stack</span>
171<span class="line">kernel: Creating interrupt stack frame</span>
172<span class="line">            SS: 0x13</span>
173<span class="line">           RSP: 0x50001000</span>
174<span class="line">        RFLAGS: 0x202</span>
175<span class="line">            CS: 0x1b</span>
176<span class="line">           RIP: 0x40000000</span>
177<span class="line">kernel: Switching to user mode</span>
178<span class="line"></span>
179<span class="line">CPU Exception: General Protection Fault</span>
180<span class="line"></span>
181<span class="line">Traceback (most recent call last)</span>
182<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(53) KernelMain</span>
183<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(185) KernelMainInner</span>
184<span class="line">
184/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/idt.nim(65) cpuGeneralProtectionFaultHandler</span>
185<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>As expected, the CPU switched to kernel mode and executed the General Protection Fault handler! Let&#39;s try another way. Let&#39;s cause a page fault by trying to access a page that&#39;s not mapped.</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/user/utask.nim</span></span>
186<span class="line"><span class="token operator">...</span></span>
187<span class="line"></span>
188<span class="line"><span class="token keyword">proc</span> <span class="token function">UserMain<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
189<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
190<span class="line"></span>
191<span class="line">  <span class="token comment"># access illegal memory</span></span>
192<span class="line">  <span class="token keyword">var</span> x <span class="token operator">=</span> <span class="token function">cast[ptr int]</span><span class="token punctuation">(</span><span class="token number">0xdeadbeef</span><span class="token punctuation">)</span></span>
193<span class="line">  x<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">42</span></span>
194<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>We should see a page fault exception at the address <code>0xdeadbeef</code>.</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">...</span>
195<span class="line">kernel: Switching to user mode</span>
196<span class="line"></span>
197<span class="line">CPU Exception: Page Fault</span>
198<span class="line">    Faulting address: 0x00000000deadbeef</span>
199<span class="line"></span>
200<span class="line">Traceback (most recent call last)</span>
201<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(53) KernelMain</span>
202<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(185) KernelMainInner</span>
203<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/idt.nim(57) cpuPageFaultHandler</span>
204<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>Great! OK, one more way. Let&#39;s try to access an address within kernel space. This should also cause a Page Fault exception, even though the address is mapped.</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/user/utask.nim</span></span>
205<span class="line"></span>
206<span class="line"><span class="token keyword">proc</span> <span class="token function">UserMain<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
207<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
208<span class="line"></span>
209<span class="line">  <span class="token comment"># access kernel memory</span></span>
210<span class="line">  <span class="token keyword">var</span> x <span class="token operator">=</span> <span class="token function">cast[ptr int]</span><span class="token punctuation">(</span><span class="token number">0xFFFF800000100000</span><span class="token punctuation">)</span>  <span class="token comment"># kernel entry point</span></span>
211<span class="line">  x<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">42</span></span>
212<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>Let&#39;s see what happens.</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">...</span>
213<span class="line">kernel: Switching to user mode</span>
214<span class="line"></span>
215<span class="line">CPU Exception: Page Fault</span>
216<span class="line">    Faulting address: 0xffff800000100000</span>
217<span class="line"></span>
218<span class="line">Traceback (most recent call last)</span>
219<span class="line">
219/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(53) KernelMain</span>
220<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(185) KernelMainInner</span>
221<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/idt.nim(57) cpuPageFaultHandler</span>
222<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>Great! This demonstrates that kernel memory is protected from access by user code.</p><h2 id="invoking-interrupts-from-user-mode" tabindex="-1"><a class="header-anchor" href="#invoking-interrupts-from-user-mode"><span>Invoking Interrupts from User Mode</span></a></h2><p>Finally, let&#39;s try to invoke an interrupt from user mode. Let&#39;s reuse the <code>isr100</code> interrupt handler we used for testing earlier.</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>
223<span class="line"><span class="token operator">...</span></span>
224<span class="line"></span>
225<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">&quot;__attribute__ ((interrupt)) $# $#$#&quot;</span><span class="token punctuation">.}</span> <span class="token operator">=</span></span>
226<span class="line">  debugln <span class="token string">&quot;Hello from isr100&quot;</span></span>
227<span class="line">  <span class="token function">quit</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
228<span class="line"></span>
229<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>
230<span class="line">  <span class="token operator">...</span></span>
231<span class="line"></span>
232<span class="line">  <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> isr100<span class="token punctuation">)</span></span>
233<span class="line">  <span class="token operator">...</span></span>
234<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Let&#39;s execute the <code>int</code> instruction from user mode.</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/user/utask.nim</span></span>
235<span class="line"></span>
236<span class="line"><span class="token keyword">proc</span> <span class="token function">UserMain<span class="token operator">*</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{.</span>exportc<span class="token punctuation">.}</span> <span class="token operator">=</span></span>
237<span class="line">  <span class="token function">NimMain</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span>
238<span class="line"></span>
239<span class="line">  <span class="token keyword">asm</span> <span class="token string">&quot;int 100&quot;</span></span>
240<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 try to run this, we are faced with a General Protection Fault exception.</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">...</span>
241<span class="line">kernel: Switching to user mode</span>
242<span class="line"></span>
243<span class="line">CPU Exception: General Protection Fault</span>
244<span class="line"></span>
245<span class="line">Traceback (most recent call last)</span>
246<span class="line">
246/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(53) KernelMain</span>
247<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/main.nim(185) KernelMainInner</span>
248<span class="line">/Users/khaledhammouda/src/github.com/khaledh/fusion/src/kernel/idt.nim(66) cpuGeneralProtectionFaultHandler</span>
249<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>The reason has to do with the <code>DPL</code> of the interrupt gate. Recall that the <code>DPL</code> of the interrupt gate must be greater than or equal to the <code>CPL</code> of the code that invokes the interrupt. In this case, the <code>DPL</code> of the interrupt gate is 0, while the <code>CPL</code> of the user code is 3. So, the CPU raises a General Protection Fault exception.</p><p>Let&#39;s fix this by allowing the <code>isr100</code> handler to be called from user mode. We need to do a couple of modifications in the <code>idt.nim</code> module to allow setting the <code>dpl</code> field of the interrupt gate.</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 operator">...</span></span>
250<span class="line"></span>
251<span class="line highlighted"><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> dpl<span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token operator">:</span> InterruptGate <span class="token operator">=</span></span>
252<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>
253<span class="line">  result <span class="token operator">=</span> <span class="token function">InterruptGate</span><span class="token punctuation">(</span></span>
254<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>
255<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>
256<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>
257<span class="line highlighted">    dpl<span class="token operator">:</span> dpl<span class="token punctuation">,</span></span>
258<span class="line">  <span class="token punctuation">)</span></span>
259<span class="line"></span>
260<span class="line highlighted"><span class="token keyword">proc</span> <span class="token function">installHandler<span class="token operator">*</span></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> dpl<span class="token operator">:</span> uint8 <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">=</span></span>
261<span class="line highlighted">  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> dpl<span class="token punctuation">)</span></span>
262<span class="line"></span>
263<span class="line"><span class="token operator">...</span></span>
264<span class="line"></span>
265<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>
266<span class="line">  <span class="token operator">...</span></span>
267<span class="line"></span>
268<span class="line highlighted">  <span class="token function">installHandler</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> isr100<span class="token punctuation">,</span> dpl <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">)</span></span>
269<span class="line">  <span class="token operator">...</span></span>
270<span class="line"></span></code></pre><div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0;"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>Let&#39;s try again.</p><div class="language-text line-numbers-mode" data-highlighter="prismjs" data-ext="text" data-title="text"><pre><code><span class="line">kernel: Switching to user mode</span>
271<span class="line">Hello from isr100</span>
272<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>Great! We can call interrupts from user mode. We&#39;re now ready to start looking into system calls.</p>`,51)]))}const o=n(p,[["render",i],["__file","17-tss.html.vue"]]),r=JSON.parse('{"path":"/osdev/17-tss.html","title":"Task State Segment","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Creating a TSS","slug":"creating-a-tss","link":"#creating-a-tss","children":[]},{"level":2,"title":"Loading the TSS","slug":"loading-the-tss","link":"#loading-the-tss","children":[]},{"level":2,"title":"Kernel Switch Stack","slug":"kernel-switch-stack","link":"#kernel-switch-stack","children":[]},{"level":2,"title":"Switching to Kernel Mode","slug":"switching-to-kernel-mode","link":"#switching-to-kernel-mode","children":[]},{"level":2,"title":"Invoking Interrupts from User Mode","slug":"invoking-interrupts-from-user-mode","link":"#invoking-interrupts-from-user-mode","children":[]}
272],"git":{"updatedTime":1745166318000},"filePathRelative":"osdev/17-tss.md","excerpt":"\\n<p>While running in user mode, an interrupt/exception or a system call causes the CPU to\\nswitch to kernel mode. This causes a change in privilege level (from CPL=3 to CPL=0). The\\nCPU cannot use the user stack while in kernel mode, since the interrupt could have been\\ncaused by something that makes the stack unusable, e.g. a page fault caused by running out\\nof stack space. So, the CPU needs to switch to a known good stack. This is where the Task\\nState Segment (TSS) comes in.</p>"}');export{o as comp,r 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.