Computer Architecture en RISC-V Bare Metal Programming - Chapter 5: It's a Trap! <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">RISC-V Bare Metal Programming - Chapter 5: It&#039;s a Trap!</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><div class="tex2jax_process"> <p>Up to this point, the RISC-V tutorial has focused on single applications running on a single hardware thread. The application's environment was composed of the processor's state and memory map. The processor state was controlled via assembly instructions, and the memory map was defined at build time via a linker script. However, modern systems are almost always multiprogrammed and will execute many applications concurrently (by interleaving their instructions in a single stream). Moreover, multiple hardware threads are common, allowing application instructions to execute simultaneously. This workflow requires a lot more care to ensure correctness and proper separation of memory. This idea was touched upon briefly in <a href="">chapter 4</a> while discussing the <b>A</b> extension which provides atomic memory operations that were used to define synchronization primitives. In addition to memory synchronization, the application must control the execution environment of all of the active hardware threads, this chapter will explore the mechanisms available for this purpose.</p> <div class="outline-2" id="outline-container-orgbf395c9"> <h2 id="orgbf395c9">The ABI</h2> <div class="outline-text-2" id="text-orgbf395c9"> <p>The examples presented thus far can all be logically separated into three layers: The application execution environment (AEE), the application binary interface (ABI), and the application code. This organisation allows for a single application to execute in a single AEE.</p> <p>The AEE is defined by the processor state and the static memory map which is defined by the linker script. The ABI describes the conventions that programs must follow and manages dynamic memory; in this case the stack. The upshot of defining an ABI layer is that application code in the third layer can interact with an abstract view of the machine implementation. This simplifies the development of applications by hiding some of the hardware details. For example, the preamble and postamble code for function calls, which are part of this ABI, were used by the application code to ensure that dynamic memory was managed correctly. These code templates can be provided by developer tools, such as high-level language compilers.</p> <p>This becomes even more important as application environments become more complex. As complexity increases in the application environment, more can be done by the ABI to hide some of the tedious details of the layer beneath it. This is where the operating system (OS) comes into play. The OS is a supervisor process which is sandwiched between the ABI and the supervisor binary interface (SBI). In this configuration, the SBI hides more of the hardware details from the OS, which provides an even more abstract view of the system to the applications. The definition of an SBI also improves the portability of the OS layer.</p> <p>Another advantage of this layered approach is that it is easier to enforce separation between applications. One application should not interfere with other applications, or with the supervisor itself. The RISC-V ISA defines three different privilege modes to enforce this. From most to least privileged, the three levels are: machine, supervisor, and user.</p> <p>ISA implementations may provide 1-3 of the defined privilege modes. All hardware implementations must provide machine mode (or M-mode). A secure embedded system may provide machine and user modes. A virtualized multiprogramming system should provide all three modes.</p> </div> </div> <div class="outline-2" id="outline-container-org4951020"> <h2 id="org4951020">What's my Pay Grade?</h2> <div class="outline-text-2" id="text-org4951020"> <p>The capabilities of the ISA implementation can be queried via the <b>misa</b> control and status register. The function illustrated in the following listing will determine which integer ISA and the number of privilege modes that are supported by the current hardware thread:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="linenr"> 1: </span> <span style="color: #00ffff;">.text</span> <span class="linenr"> 2: </span> <span style="color: #00ffff;">.align</span> 2 <span class="linenr"> 3: </span> <span style="color: #00ffff;">.global</span> __system_check <span class="linenr"> 4: </span><span style="color: #87cefa;">__system_check</span>: <span class="linenr"> 5: </span> # Input <span class="linenr"> 6: </span> # None <span class="linenr"> 7: </span> # <span class="linenr"> 8: </span> # Returns <span class="linenr"> 9: </span> # - a0: The number of supported privilege modes (1, 2 or 3). <span class="linenr">10: </span> # - a1: The register width used by the ISA (in bytes). <span class="coderef-off" id="coderef-load-misa"><span class="linenr">11: </span> <span style="color: #00ffff;">csrr</span> t0, misa # Load misa into t0</span> <span class="coderef-off" id="coderef-load-xlen"><span class="linenr">12: </span> <span style="color: #00ffff;">li</span> a1, 4 # Load minimum register width</span> <span class="linenr">13: </span> <span style="color: #00ffff;">li</span> a0, 1 # M-mode is always supported <span class="linenr">14: </span> # Probe for user-mode <span class="coderef-off" id="coderef-umode-mask"><span class="linenr">15: </span> <span style="color: #00ffff;">lui</span> t1, 0x100 # Set the u-mode mask in t1</span> <span class="linenr">16: </span> <span style="color: #00ffff;">and</span> t1, t0, t1 <span class="coderef-off" id="coderef-check-umode"><span class="linenr">17: </span> <span style="color: #00ffff;">beqz</span> t1, 1f # Determine if the U-mode bit is set in misa</span> <span class="coderef-off" id="coderef-set-umode"><span class="linenr">18: </span> <span style="color: #00ffff;">addi</span> a0, a0, 1 # U-mode is available, increment a0</span> <span class="linenr">19: </span><span style="color: #87cefa;">1</span>: # Probe for supervisor-mode <span class="coderef-off" id="coderef-smode-mask"><span class="linenr">20: </span> <span style="color: #00ffff;">lui</span> t1, 0x40 # Set the S-mode mask in t1</span> <span class="linenr">21: </span> <span style="color: #00ffff;">and</span> t1, t0, t1 <span class="coderef-off" id="coderef-check-smode"><span class="linenr">22: </span> <span style="color: #00ffff;">beqz</span> t1, 2f # Determine if the S-mode bit is set in misa</span> <span class="coderef-off" id="coderef-set-smode"><span class="linenr">23: </span> <span style="color: #00ffff;">addi</span> a0, a0, 1 # S-mode is available, increment a0</span> <span class="linenr">24: </span><span style="color: #87cefa;">2</span>: # Determine register width <span class="coderef-off" id="coderef-have-xlen"><span class="linenr">25: </span> <span style="color: #00ffff;">bgez</span> t0, 3f # Determine if a1 holds the register width</span> <span class="coderef-off" id="coderef-scale-xlen"><span class="linenr">26: </span> <span style="color: #00ffff;">slli</span> a1, a1, 1 # Multiply register width by 2</span> <span class="linenr">27: </span> <span style="color: #00ffff;">slli</span> t0, t0, 1 <span class="linenr">28: </span> <span style="color: #00ffff;">j</span> 2b <span class="linenr">29: </span><span style="color: #87cefa;">3</span>: <span class="linenr">30: </span> <span style="color: #00ffff;">ret</span> <span class="linenr">31: </span> </pre></div> <p>This function loads the <b>misa</b> Control and Status Register (CSR) into the temporary register <b>t0</b> on line <a class="coderef" href="#coderef-load-misa" onmouseout="CodeHighlightOff(this, 'coderef-load-misa');" onmouseover="CodeHighlightOn(this, 'coderef-load-misa');">11</a> using the <code>csrr</code> pseudo instruction. The minimum register width is 4-bytes, therefore the immediate 4 is loaded into register <b>a1</b> as an initial value (line <a class="coderef" href="#coderef-load-xlen" onmouseout="CodeHighlightOff(this, 'coderef-load-xlen');" onmouseover="CodeHighlightOn(this, 'coderef-load-xlen');">12</a>). Moreover, machine-mode is required by hardware implementations, thus the initial value of <b>a1</b> is 1.</p> <p>The least-significant 26-bits of the <b>misa</b> CSR are flags which indicate supported extensions; one for each letter of the alphabet. The <b>S</b> and <b>U</b> extensions are for supervisor and user mode respectively. Therefore, user mode will be available if bit 20 is set to 1. A bit mask is created on line <a class="coderef" href="#coderef-umode-mask" onmouseout="CodeHighlightOff(this, 'coderef-umode-mask');" onmouseover="CodeHighlightOn(this, 'coderef-umode-mask');">15</a>.</p> <blockquote><p>Since the mask is an immediate value that is wider than what is allowed by RISC-V I-type instructions, the <code>lui</code> instruction can be used to load the 20-bit immediate value then shift it left by 12-bits with a single instruction. Thus the immediate value 0x100 becomes 0x100000 when loaded following the load operation.</p> </blockquote> <p>A bit-wise <b>AND</b> is performed using the bit-mask and the <b>misa</b> CSR value to determine if user-mode is available. If the result of the <code>and</code> instruction is zero on line <a class="coderef" href="#coderef-check-umode" onmouseout="CodeHighlightOff(this, 'coderef-check-umode');" onmouseover="CodeHighlightOn(this, 'coderef-check-umode');">17</a>, user-mode is not supported. Otherwise the value of <b>a1</b> is incremented on line <a class="coderef" href="#coderef-set-umode" onmouseout="CodeHighlightOff(this, 'coderef-set-umode');" onmouseover="CodeHighlightOn(this, 'coderef-set-umode');">18</a>.</p> <p>Similarly supervisor mode is supported if bit 18 is set to 1. A bit mask is created on line <a class="coderef" href="#coderef-smode-mask" onmouseout="CodeHighlightOff(this, 'coderef-smode-mask');" onmouseover="CodeHighlightOn(this, 'coderef-smode-mask');">20</a>, then a bit-wise <b>AND</b> is performed with the value if the <b>misa</b> CSR on the next line. If the result is zero, then supervisor mode is not supported. Otherwise the number of privilege modes is incremented by 1.</p> <p>The final step of the <code>__system_check</code> function is to determine the width of the hart's registers. The <b>misa</b> CSR's most-significant 2-bits encodes the width of the registers used by the ISA: 1) 32-bits, 2) 64-bits, 3) 128-bits. Determining this is complicated by the fact that the CSR's width is not known prior to checking this field. To overcome this, a check is performed to determine if the register's value is negative, in which case the most-significant bit must be set to 1. Therefore the number of bytes in <b>a1</b> will be multiplied by 2 (by shifting it to the left by 1 bit on line <a class="coderef" href="#coderef-scale-xlen" onmouseout="CodeHighlightOff(this, 'coderef-scale-xlen');" onmouseover="CodeHighlightOn(this, 'coderef-scale-xlen');">26</a>), the value of <b>t0</b> is shifted by 1 to the left, and the check is performed again. If the value of t0 is determined to be positive on line <a class="coderef" href="#coderef-have-xlen" onmouseout="CodeHighlightOff(this, 'coderef-have-xlen');" onmouseover="CodeHighlightOn(this, 'coderef-have-xlen');">25</a> (i.e. the msb is 0), then the <code>__system_check</code> function has completed its probe. The following listing illustrates the main program which performs the system check:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="linenr">1: </span> <span style="color: #00ffff;">.section</span> <span style="color: #ffa07a;">".text.init"</span> <span class="linenr">2: </span> <span style="color: #00ffff;">.align</span> 2 <span class="linenr">3: </span> <span style="color: #00ffff;">.global</span> _start <span class="linenr">4: </span> <span style="color: #00ffff;">.global</span> _stack_end <span class="linenr">5: </span><span style="color: #87cefa;">_start</span>: <span class="linenr">6: </span> <span style="color: #00ffff;">la</span> sp, _stack_end <span class="coderef-off" id="coderef-call-systemcheck"><span class="linenr">7: </span> <span style="color: #00ffff;">call</span> __system_check</span> <span class="linenr">8: </span><span style="color: #87cefa;">stop</span>: <span style="color: #00ffff;">j</span> stop <span class="linenr">9: </span> </pre></div> <p>The <code>__system_check</code> function is called on line <a class="coderef" href="#coderef-call-systemcheck" onmouseout="CodeHighlightOff(this, 'coderef-call-systemcheck');" onmouseover="CodeHighlightOn(this, 'coderef-call-systemcheck');">7</a>. When this function returns the register <b>a0</b> should hold the number of supported privilege modes, and register <b>a1</b> should hold the number of bytes in a register. If this program is run in <code>qemu</code>, the <code>info registers</code> command can be used at the console to determine the hardware details:</p> <div class="org-src-container"> <pre class="src src-sh"> make chapter5 qemu-system-riscv64 -M virt -serial /dev/null -nographic -kernel chapter5.elf QEMU 3.1.0 monitor - type <span style="color: #ffa07a;">'help'</span> for more information (qemu) info registers pc 000000008000000c mhartid 0000000000000000 mstatus 0000000000000000 mip 0000000000000000 mie 0000000000000000 mideleg 0000000000000000 medeleg 0000000000000000 mtvec 0000000000000000 mepc 0000000000000000 mcause 0000000000000000 zero 0000000000000000 ra 000000008000000c sp 0000000080009000 gp 0000000000000000 tp 0000000000000000 t0 000000000028225a t1 0000000000040000 t2 0000000000000000 s0 0000000000000000 s1 0000000000000000 a0 0000000000000003 a1 0000000000000008 ... </pre></div> <p>The value of <b>a0</b> is 3, therefore the <code>qemu</code> VirtIO platform supports all three privilege modes. The value of <b>a1</b> is 8, which means that the register width is 64-bits (8 bytes). This value could be used as a stack offset allowing for the definition of the function call preamble and postamble as part of a library. This library could then be used to define an operating system's ABI.</p> </div> </div> <div class="outline-2" id="outline-container-org59973e7"> <h2 id="org59973e7">It's a Trap!</h2> <div class="outline-text-2" id="text-org59973e7"> <p>Typically, systems should run in the most restricted environment possible in order to minimize catastrophes in the event of a system fault. However, when an exceptional event occurs, the system may want to raise its privilege level in order to deal with it. These types of events are often associated with an interrupt.</p> <p>The machine-mode status CSR, <b>mstatus</b>, allows some control over a hart's operating state, including enabling or disabling global interrupts. Three fields are defined in the register's least significant four bits for this purpose; one for each of the privilege modes.</p> <blockquote><p>specific interrupt types for each privilege mode must be enabled individually via the <b>mie</b> register which will be described later</p> </blockquote> <p>The fields defined in the <b>mstatus</b> register are illustrated in the following table:</p> <table border="2" cellpadding="6" cellspacing="0" frame="hsides" rules="groups"><caption class="t-above"><span class="table-number">Table 1:</span> mstatus CSR register</caption> <colgroup><col class="org-right" /><col class="org-left" /><col class="org-left" /><col class="org-left" /><col class="org-left" /><col class="org-left" /><col class="org-left" /><col class="org-left" /><col class="org-left" /></colgroup><thead><tr><th class="org-right" scope="col">Bit</th> <th class="org-left" scope="col">0</th> <th class="org-left" scope="col">1</th> <th class="org-left" scope="col">2</th> <th class="org-left" scope="col">3</th> <th class="org-left" scope="col">4</th> <th class="org-left" scope="col">5</th> <th class="org-left" scope="col">6</th> <th class="org-left" scope="col">7</th> </tr></thead><tbody><tr><td class="org-right">0</td> <td class="org-left">UIE</td> <td class="org-left">SIE</td> <td class="org-left"> </td> <td class="org-left">MIE</td> <td class="org-left">UPIE</td> <td class="org-left">SPIE</td> <td class="org-left"> </td> <td class="org-left">MPIE</td> </tr><tr><td class="org-right">+8</td> <td class="org-left">MPP</td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left">MPP[0]</td> <td class="org-left">MPP[1]</td> <td class="org-left">FS[0]</td> <td class="org-left">FS[1]</td> <td class="org-left">XS[0]</td> </tr><tr><td class="org-right">+16</td> <td class="org-left">XS[1]</td> <td class="org-left">MPRV</td> <td class="org-left">SUM</td> <td class="org-left">MXR</td> <td class="org-left">TVM</td> <td class="org-left">TW</td> <td class="org-left">TSR</td> <td class="org-left"> </td> </tr><tr><td class="org-right">+24</td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> </tr><tr><td class="org-right">+32</td> <td class="org-left">UXL[0]</td> <td class="org-left">UXL[1]</td> <td class="org-left">SXL[0]</td> <td class="org-left">SXL[1]</td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> </tr><tr><td class="org-right">+40</td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> </tr><tr><td class="org-right">+48</td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> </tr><tr><td class="org-right">+56</td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left"> </td> <td class="org-left">SD</td> </tr></tbody></table><p>The <b>UIE</b>, <b>SIE</b>, and <b>MIE</b> fields will enable interrupts globally for the user, supervisor, and machine modes respectively. If the $x$IE fields value is set to 1, interrupts will be enabled globally for privilege mode \(x\) and any privilege mode \(y &lt; x\) provided $y$IE is also set to 1. If the hart is operating at privilege level \(x\), interrupts at privilege levels inferior to \(x\) will be disabled regardless of the state of the associated interrupt bit in <b>mstatus</b>.</p> <p>To be of any use, there must be a mechanism to handle interrupts. The <b>BASE</b> field of the <b>mtvec</b> CSR can be set to the base address of a trap-vector to handle interrupts. The <b>MODE</b> field, that occupies the least-significant two bits of <b>mtvec</b>, specify the trap mode. When the <b>MODE</b> field is set to 0, the trap mode will be set to call the handler directly. Otherwise the base address expresses the base of a vector of trap handlers; one for each interrupt type indexed by the interrupt code. For the time being, a single interrupt handler will be used to dispatch to the appropriate handler for interrupts or exceptions.</p> <p>The code that follows illustrates a skeleton for a trap handler implementation in direct mode:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="linenr"> 1: </span> <span style="color: #00ffff;">.text</span> <span class="linenr"> 2: </span> <span style="color: #00ffff;">.align</span> 2 <span class="linenr"> 3: </span> <span style="color: #00ffff;">.global</span> trap_handler <span class="linenr"> 4: </span><span style="color: #87cefa;">trap_handler</span>: <span class="linenr"> 5: </span> # Trap handler preamble (save registers). <span class="coderef-off" id="coderef-trap-load scratch"><span class="linenr"> 6: </span> <span style="color: #00ffff;">csrrw</span> a0, mscratch, a0</span> <span class="linenr"> 7: </span> <span style="color: #00ffff;">sd</span> a1, 0(a0) <span class="linenr"> 8: </span> <span style="color: #00ffff;">sd</span> a2, 8(a0) <span class="linenr"> 9: </span> <span style="color: #00ffff;">sd</span> a3, 16(a0) <span class="linenr">10: </span> <span style="color: #00ffff;">sd</span> a4, 24(a0) <span class="linenr">11: </span> # Decode the cause of the interrupt. <span class="coderef-off" id="coderef-trap-get cause"><span class="linenr">12: </span> <span style="color: #00ffff;">csrr</span> a1, mcause</span> <span class="coderef-off" id="coderef-trap-check exception"><span class="linenr">13: </span> <span style="color: #00ffff;">bgez</span> a1, exception</span> <span class="linenr">14: </span><span style="color: #87cefa;">interrupt</span>: <span class="linenr">15: </span> <span style="color: #00ffff;">andi</span> a1, a1, 0x3f # Isolate the cause field <span class="linenr">16: </span> # TODO: Dispatch to specific interrupt handler <span class="linenr">17: </span> <span style="color: #00ffff;">j</span> trap_handler_restore_state <span class="linenr">18: </span><span style="color: #87cefa;">exception</span>: <span class="linenr">19: </span> <span style="color: #00ffff;">addi</span> a1, a1, 0x3f # Isolate the cause field <span class="linenr">20: </span> # TODO: Dispatch to specific exception handler <span class="linenr">21: </span><span style="color: #87cefa;">trap_handler_restore_state</span>: <span class="linenr">22: </span> <span style="color: #00ffff;">ld</span> a4, 24(a0) <span class="linenr">23: </span> <span style="color: #00ffff;">ld</span> a3, 16(a0) <span class="linenr">24: </span> <span style="color: #00ffff;">ld</span> a2, 8(a0) <span class="linenr">25: </span> <span style="color: #00ffff;">ld</span> a1, 0(a0) <span class="linenr">26: </span> <span style="color: #00ffff;">csrrw</span> a0, mscratch, a0 <span class="linenr">27: </span> <span style="color: #00ffff;">mret</span> </pre></div> <p>The first instruction on line <a class="coderef" href="#coderef-trap-load scratch" onmouseout="CodeHighlightOff(this, 'coderef-trap-load scratch');" onmouseover="CodeHighlightOn(this, 'coderef-trap-load scratch');">6</a> will atomically swap the values of the <b>mscratch</b> CSR and <b>a0</b>. This register is defined to provide additional data to trap handlers. Typically, this should be set to an memory address of a buffer where register data can be saved while the handler is active.</p> <p>The next four lines save the contents of registers <b>a1</b>-<b>a4</b> in the memory buffer located at the address in <b>mscratch</b>, then the value of the <b>mcause</b> CSR is copied into <b>a1</b> on line <a class="coderef" href="#coderef-trap-get cause" onmouseout="CodeHighlightOff(this, 'coderef-trap-get cause');" onmouseover="CodeHighlightOn(this, 'coderef-trap-get cause');">12</a>. The <b>mcause</b> register is used to indicate the cause of synchronous and asynchronous exceptions. If the most significant bit in this register is zero, then the trap was caused by a synchronous exception. This can be determined by testing the value of <b>a1</b> to see if it is greater than or equal to zero (on line <a class="coderef" href="#coderef-trap-check exception" onmouseout="CodeHighlightOff(this, 'coderef-trap-check exception');" onmouseover="CodeHighlightOn(this, 'coderef-trap-check exception');">13</a>; if the msb is 1, the register will be negative and the execution will fall through to the interrupt handler code.</p> <p>To use the trap handler, it's address must be set in the base field of the <b>mtvec</b> CSR. This is illustrated in the following program:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="linenr"> 1: </span> <span style="color: #00ffff;">.section</span> <span style="color: #ffa07a;">".text.init"</span> <span class="linenr"> 2: </span> <span style="color: #00ffff;">.align</span> 2 <span class="linenr"> 3: </span> <span style="color: #00ffff;">.global</span> _start <span class="linenr"> 4: </span> <span style="color: #00ffff;">.global</span> _stack_end <span class="linenr"> 5: </span><span style="color: #87cefa;">_start</span>: <span class="linenr"> 6: </span> <span style="color: #00ffff;">la</span> sp, _stack_end <span class="coderef-off" id="coderef-load scratch"><span class="linenr"> 7: </span> <span style="color: #00ffff;">la</span> a0, scratch</span> <span class="coderef-off" id="coderef-set scratch"><span class="linenr"> 8: </span> <span style="color: #00ffff;">csrrw</span> a0, mscratch, a0</span> <span class="coderef-off" id="coderef-load trap handler"><span class="linenr"> 9: </span> <span style="color: #00ffff;">la</span> a0, trap_handler</span> <span class="coderef-off" id="coderef-set trap handler"><span class="linenr">10: </span> <span style="color: #00ffff;">csrrw</span> a0, mtvec, a0</span> <span class="linenr">11: </span> <span style="color: #00ffff;">call</span> __system_check <span class="linenr">12: </span><span style="color: #87cefa;">stop</span>: <span style="color: #00ffff;">j</span> stop <span class="linenr">13: </span> <span style="color: #00ffff;">.bss</span> <span class="coderef-off" id="coderef-define scratch"><span class="linenr">14: </span><span style="color: #87cefa;">scratch</span>: .dword 0, 0, 0, 0</span> </pre></div> <p>The scratch area where the register state can be saved is defined on line <a class="coderef" href="#coderef-define scratch" onmouseout="CodeHighlightOff(this, 'coderef-define scratch');" onmouseover="CodeHighlightOn(this, 'coderef-define scratch');">14</a>. This allocates 32 bytes of space to save the contents of up to 4 registers which is enough for the current <code>trap_handler</code> implementation. The address of the scratch is loaded into register <b>a0</b> on line <a class="coderef" href="#coderef-load scratch" onmouseout="CodeHighlightOff(this, 'coderef-load scratch');" onmouseover="CodeHighlightOn(this, 'coderef-load scratch');">7</a>. This register's value is then swapped with the value of the <b>mscratch</b> CSR on line <a class="coderef" href="#coderef-set scratch" onmouseout="CodeHighlightOff(this, 'coderef-set scratch');" onmouseover="CodeHighlightOn(this, 'coderef-set scratch');">8</a>.</p> <p>The address of the trap handler function is loaded into register <b>a0</b> on line <a class="coderef" href="#coderef-load trap handler" onmouseout="CodeHighlightOff(this, 'coderef-load trap handler');" onmouseover="CodeHighlightOn(this, 'coderef-load trap handler');">9</a>, then it is swapped with the contents of the <b>mtvec</b> CSR on line <a class="coderef" href="#coderef-set trap handler" onmouseout="CodeHighlightOff(this, 'coderef-set trap handler');" onmouseover="CodeHighlightOn(this, 'coderef-set trap handler');">10</a>. The <b>MODE</b> field is left as zero to set the trap mode to direct; which will cause all synchronous and asynchronous interrupts to branch to the base address.</p> </div> </div> <div class="outline-2" id="outline-container-orga01113b"> <h2 id="orga01113b">What's the Time?</h2> <div class="outline-text-2" id="text-orga01113b"> <p>A platform's real-time counter is one of the possible sources of asynchronous exceptions that can cause an interrupt. The timer is typically external to the processing core. The VirtIO machine of the QEMU emulator includes the core-level interrupt module (CLINT). This module defines the <b>mtime</b> register that exposes the current value of the real-time counter. This value expresses the number of clock cycles that have elapsed since the processor was reset. This does not represent the real time, but a count of real-time intervals (determined by the oscillator frequency).</p> <p>The <b>mtime</b> register is mapped to a particular address in physical memory. The actual address is specified in the memory map of the VirtIO machine in the QEMU system (see <a href=";a=blob_plain;f=hw/riscv/virt.c;hb=refs/heads/stable-3.1">hw/riscv/virt.c</a>). The listing that follows illustrates a function to retrieve the current real-time counter value:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="coderef-off" id="coderef-clint base"><span class="linenr"> 1: </span> <span style="color: #00ffff;">.equ</span> CLINT_BASE, 0x2000000 # The base address of the CLINT module</span> <span class="coderef-off" id="coderef-mtime offset"><span class="linenr"> 2: </span> <span style="color: #00ffff;">.equ</span> CLINT_MTIME, 0xbff8 # The offset of the MTIME register</span> <span class="coderef-off" id="coderef-ld-mtime macro"><span class="linenr"> 3: </span> <span style="color: #00ffff;">.macro</span> ld_mtime rd # Macro to access the MTIME memory mapped register</span> <span class="linenr"> 4: </span> <span style="color: #00ffff;">li</span> t0, CLINT_BASE <span class="linenr"> 5: </span> <span style="color: #00ffff;">li</span> t1, CLINT_MTIME <span class="coderef-off" id="coderef-mtime addr"><span class="linenr"> 6: </span> <span style="color: #00ffff;">add</span> t0, t0, t1 # Determine the absolute address of MTIME</span> <span class="coderef-off" id="coderef-read counter"><span class="linenr"> 7: </span> <span style="color: #00ffff;">ld</span> \rd, 0(t0) # Read the counter value</span> <span class="linenr"> 8: </span> <span style="color: #00ffff;">.endm</span> <span class="linenr"> 9: </span> <span class="linenr">10: </span> <span style="color: #00ffff;">.text</span> <span class="linenr">11: </span> <span style="color: #00ffff;">.align</span> 2 <span class="linenr">12: </span> <span style="color: #00ffff;">.global</span> __clock_cycle <span class="linenr">13: </span><span style="color: #87cefa;">__clock_cycle</span>: <span class="linenr">14: </span> # Retrieve the current value of the real-time counter. <span class="linenr">15: </span> # <span class="linenr">16: </span> # Inputs: None <span class="linenr">17: </span> # <span class="linenr">18: </span> # Returns: <span class="linenr">19: </span> # - a0: The current value of the mtime register. <span class="linenr">20: </span> <span style="color: #00ffff;">ld</span> ld_mtime a0 <span class="linenr">21: </span> <span style="color: #00ffff;">ret</span> </pre></div> <p>The CLINT_BASE symbol is defined on line <a class="coderef" href="#coderef-clint base" onmouseout="CodeHighlightOff(this, 'coderef-clint base');" onmouseover="CodeHighlightOn(this, 'coderef-clint base');">1</a>, its value is the absolute base address of the memory mapped registers of the CLINT module (see <a href=";a=blob_plain;f=include/hw/riscv/sifive_clint.h;hb=refs/heads/stable-3.1">include/hw/riscv/sifive_clint.h</a> of the QEMU source). The CLINT_MTIME symbol, defined on line <a class="coderef" href="#coderef-mtime offset" onmouseout="CodeHighlightOff(this, 'coderef-mtime offset');" onmouseover="CodeHighlightOn(this, 'coderef-mtime offset');">2</a>, specifies the offset of the <b>mtime</b> register relative to the CLINT's base memory address. The offset is added to the base address and its result stored in register <b>t0</b> on line <a class="coderef" href="#coderef-mtime addr" onmouseout="CodeHighlightOff(this, 'coderef-mtime addr');" onmouseover="CodeHighlightOn(this, 'coderef-mtime addr');">6</a>. Finally the value of the the real-time counter is retrieved on line <a class="coderef" href="#coderef-read counter" onmouseout="CodeHighlightOff(this, 'coderef-read counter');" onmouseover="CodeHighlightOn(this, 'coderef-read counter');">7</a>. All of these operations are defined in a macro starting on line <a class="coderef" href="#coderef-ld-mtime macro" onmouseout="CodeHighlightOff(this, 'coderef-ld-mtime macro');" onmouseover="CodeHighlightOn(this, 'coderef-ld-mtime macro');">3</a>.</p> <p>The <b>mtime</b> register is useful to determine the time since the board was reset. However, it cannot generate interrupts by itself. The <b>mtimecmp</b> memory mapped register will cause a timer interrupt to be posted when its value is less than the value contained in <b>mtime</b>. In other words, if when the periodically increasing value of <b>mtime</b> exceeds that contained in <b>mtimecmp</b>, a timer interrupt will be posted (provided that timer interrupts are enabled). Therefore to receive an interrupt after some fixed interval of time, the current value of <b>mtime</b> must be retrieved, then the timeout value must be added thereto and the result saved in the <b>mtimecmp</b> register. This process is illustrated in the following listing:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="coderef-off" id="coderef-mtimecmp_offset"><span class="linenr"> 1: </span> <span style="color: #00ffff;">.equ</span> CLINT_MTIMECMP, 0x4000 # The offset of the MTIMECMP register</span> <span class="linenr"> 2: </span> <span style="color: #00ffff;">.macro</span> st_mtimecmp rs <span class="linenr"> 3: </span> <span style="color: #00ffff;">li</span> t0, CLINT_BASE <span class="linenr"> 4: </span> <span style="color: #00ffff;">li</span> t1, CLINT_MTIMECMP <span class="linenr"> 5: </span> <span style="color: #00ffff;">add</span> t1, t0, t1 <span class="linenr"> 6: </span> <span style="color: #00ffff;">sd</span> \rs, 0(t1) <span class="linenr"> 7: </span> <span style="color: #00ffff;">.endm</span> <span class="linenr"> 8: </span> <span style="color: #00ffff;">.global</span> __timer_create <span class="linenr"> 9: </span><span style="color: #87cefa;">__timer_create</span>: <span class="linenr">10: </span> # Set a timer to trigger an interrupt when a given number of <span class="linenr">11: </span> # clock cycles have elapsed. <span class="linenr">12: </span> # <span class="linenr">13: </span> # Inputs: <span class="linenr">14: </span> # - a0: The timeout value in clock cycles. <span class="linenr">15: </span> <span style="color: #00ffff;">ld_mtime</span> t1 <span class="linenr">16: </span> <span style="color: #00ffff;">ld</span> t1, 0(t1) <span class="coderef-off" id="coderef-set_timeout"><span class="linenr">17: </span> <span style="color: #00ffff;">add</span> a0, a0, t1 # Add the timeout to the clock cycle</span> <span class="linenr">18: </span> <span style="color: #00ffff;">st_mtimecmp</span> a0 <span class="linenr">19: </span> <span style="color: #00ffff;">ret</span> </pre></div> <p>The <code>__timer_create</code> function will set a timer to trigger an interrupt after the given number of clock cycles have elapsed. This code re-uses the macro defined previously to read the current value of the real-time counter, then adds the desired number of cycles thereto, and writes the result to the <b>mtimecmp</b> register. When <b>mtime</b>'s value is greater than the value in <b>mtimecmp</b>, the MTIP field of the <b>mip</b> CSR register will be asserted to indicate that a timer interrupt is pending, and the trap handler will be called. The following code will set up this process:</p> <div class="org-src-container"> <pre class="src src-asm" id="org0bbc010"> <span class="linenr"> 1: </span> <span style="color: #00ffff;">.section</span> <span style="color: #ffa07a;">".text.init"</span> <span class="linenr"> 2: </span> <span style="color: #00ffff;">.align</span> 2 <span class="linenr"> 3: </span> <span style="color: #00ffff;">.global</span> _start <span class="linenr"> 4: </span> <span style="color: #00ffff;">.global</span> _stack_end <span class="linenr"> 5: </span> <span style="color: #00ffff;">.global</span> CLOCK_MONOTONIC <span class="linenr"> 6: </span><span style="color: #87cefa;">_start</span>: <span class="linenr"> 7: </span> <span style="color: #00ffff;">la</span> sp, _stack_end <span class="coderef-off" id="coderef-load-mtrap"><span class="linenr"> 8: </span> <span style="color: #00ffff;">la</span> t0, __mtrap_handler # Load trap vector address</span> <span class="linenr"> 9: </span> <span style="color: #00ffff;">csrrw</span> zero, mtvec, t0 <span class="linenr">10: </span> <span style="color: #00ffff;">li</span> t0, 0b1&lt;&lt;3 <span class="linenr">11: </span> <span style="color: #00ffff;">csrrs</span> t0, mstatus, t0 # Enable interrupts globally (ref:set-mstatus.MIE) <span class="linenr">12: </span> <span style="color: #00ffff;">li</span> t0, 0b1&lt;&lt;7 <span class="linenr">13: </span> <span style="color: #00ffff;">csrrs</span> t0, mie, t0 # Enable timer interrupts (ref:set-mie.MTIE) <span class="coderef-off" id="coderef-load-timeout"><span class="linenr">14: </span><span style="color: #87cefa;">1</span>: <span style="color: #00ffff;">li</span> a0, 0x10000 # Set the timeout value</span> <span class="coderef-off" id="coderef-trap-settimer"><span class="linenr">15: </span> <span style="color: #00ffff;">call</span> __timer_create # Set the timer</span> <span class="coderef-off" id="coderef-wfi"><span class="linenr">16: </span> <span style="color: #00ffff;">wfi</span> # Wait for interrupts</span> <span class="linenr">17: </span> <span style="color: #00ffff;">j</span> 1b <span class="linenr">18: </span> <span class="linenr">19: </span> <span style="color: #00ffff;">.align</span> 2 <span class="coderef-off" id="coderef-mtrap-handler"><span class="linenr">20: </span><span style="color: #87cefa;">__mtrap_handler</span>: # Machine interrupt handler</span> <span class="coderef-off" id="coderef-trap-get-cause"><span class="linenr">21: </span> <span style="color: #00ffff;">csrrc</span> t0, mcause, zero # Get the cause of the interrupt</span> <span class="coderef-off" id="coderef-trap-exception"><span class="linenr">22: </span> <span style="color: #00ffff;">bgez</span> t0, 2f # Exit on an exception</span> <span class="linenr">23: </span> <span style="color: #00ffff;">slli</span> t0, t0, 1 <span class="linenr">24: </span> <span style="color: #00ffff;">srli</span> t0, t0, 1 <span class="linenr">25: </span> <span style="color: #00ffff;">li</span> t1, 7 # The timer interrupt has code 7. <span class="coderef-off" id="coderef-trap-check-mtip"><span class="linenr">26: </span> <span style="color: #00ffff;">bne</span> t0, t1, 2f # Check for timer interrupts</span> <span class="linenr">27: </span> <span style="color: #00ffff;">addi</span> s0, s0, 1 # Increment the interrupt count. <span class="coderef-off" id="coderef-trap-mret"><span class="linenr">28: </span><span style="color: #87cefa;">2</span>: <span style="color: #00ffff;">mret</span> # Machine trap return</span> </pre></div> <p>After setting up the stack, this program loads the address for the trap handler on line <a class="coderef" href="#coderef-load-mtrap" onmouseout="CodeHighlightOff(this, 'coderef-load-mtrap');" onmouseover="CodeHighlightOn(this, 'coderef-load-mtrap');">8</a>, and stores this address in the <b>mtvec</b> CSR. Machine-mode interrupts are then enabled globally by setting bit 3 of the <b>mstatus</b> CSR to 1 (on line <a class="coderef" href="#coderef-set-mstatus.MIE" onmouseout="CodeHighlightOff(this, 'coderef-set-mstatus.MIE');" onmouseover="CodeHighlightOn(this, 'coderef-set-mstatus.MIE');">11</a>), and M-mode timer interrupts are enabled (on line <a class="coderef" href="#coderef-set-mie.MTIE" onmouseout="CodeHighlightOff(this, 'coderef-set-mie.MTIE');" onmouseover="CodeHighlightOn(this, 'coderef-set-mie.MTIE');">13</a>) by setting bit 7 of the <b>mie</b> CSR to 1. On line <a class="coderef" href="#coderef-load-timeout" onmouseout="CodeHighlightOff(this, 'coderef-load-timeout');" onmouseover="CodeHighlightOn(this, 'coderef-load-timeout');">14</a>, an immediate value is loaded into register <b>a0</b>. This value will be used to create the timer on line <a class="coderef" href="#coderef-trap-settimer" onmouseout="CodeHighlightOff(this, 'coderef-trap-settimer');" onmouseover="CodeHighlightOn(this, 'coderef-trap-settimer');">15</a>. Once the timer is armed, the <code>wfi</code> instruction is used on line <a class="coderef" href="#coderef-wfi" onmouseout="CodeHighlightOff(this, 'coderef-wfi');" onmouseover="CodeHighlightOn(this, 'coderef-wfi');">16</a> to wait for an exception to occur at which point control jumps to the interrupt handler. When the handler returns, control jumps back to line <a class="coderef" href="#coderef-load-timeout" onmouseout="CodeHighlightOff(this, 'coderef-load-timeout');" onmouseover="CodeHighlightOn(this, 'coderef-load-timeout');">14</a>, and the timer is armed again. This should cause periodic calls to the trap vector.</p> <p>A machine-level trap handler is defined on line <a class="coderef" href="#coderef-mtrap-handler" onmouseout="CodeHighlightOff(this, 'coderef-mtrap-handler');" onmouseover="CodeHighlightOn(this, 'coderef-mtrap-handler');">20</a>. This handler will increment the value in register <b>s0</b> every time a timer exception is triggered. The cause of the interrupt is determined on line <a class="coderef" href="#coderef-trap-get-cause" onmouseout="CodeHighlightOff(this, 'coderef-trap-get-cause');" onmouseover="CodeHighlightOn(this, 'coderef-trap-get-cause');">21</a> which atomically reads the value of the <b>mcause</b> CSR and sets its value to zero. If the value of this register was greater-than, or equal to, zero (line <a class="coderef" href="#coderef-trap-exception" onmouseout="CodeHighlightOff(this, 'coderef-trap-exception');" onmouseover="CodeHighlightOn(this, 'coderef-trap-exception');">22</a>), the interrupt was caused by a synchronous exception (whereby the most-significant bit of the register will be set to 1). In the case of a synchronous exception, the handler simply exists by calling the <code>mret</code> instruction which returns control to the instruction that was executing when the exception occurred. Otherwise the next two lines will shift off the most significant bit (i.e. set it to zero). The interrupt code is checked on line <a class="coderef" href="#coderef-trap-check-mtip" onmouseout="CodeHighlightOff(this, 'coderef-trap-check-mtip');" onmouseover="CodeHighlightOn(this, 'coderef-trap-check-mtip');">26</a>, if it corresponds with the timer interrupt, the value of <b>s0</b> is incremented by 1.</p> <p>The state of the hart can be inspected via the <code>info registers</code> command in <code>qemu</code>. If the timing of the snapshot is such that the trap handler is executing the machine CSRs will have the following state:</p> <div class="org-src-container"> <pre class="src src-sh"> (qemu) info registers pc 000000008000004c mhartid 0000000000000000 mstatus 0000000000001880 mip 0000000000000080 mie 0000000000000080 mideleg 0000000000000000 medeleg 0000000000000000 mtvec 0000000080000048 mepc 0000000080000040 mcause 8000000000000007 </pre></div> <p>As usual, the <b>pc</b> register shows the current address of the active instruction, however, in this case control has jumped into the trap handler. When an exception is triggered, the following operations are executed atomically:</p> <ol class="org-ol"><li>Interrupts are disabled globally (bit 3 of <b>mstatus</b> is set to 0).</li> <li>The <b>mstatus.MPIE</b> field (which represents the previous global interrupt mode) is set the value of <b>mstatus.MIE</b></li> <li>Interrupts are disabled globally by setting the <b>mstatus.MIE</b> field is set to zero.</li> <li>The <b>mstatus.MPP</b> field (bits 12:11) is set to 0b11 which indicates the privilege level prior to the exception being raised.</li> <li>The address of the instruction that follows the last one to execute before the exception was raised is saved in the <b>mepc</b> register.</li> <li>The cause of the exception is written in register <b>mcause</b>.</li> <li>The <b>pc</b> register is set to the address in <b>mtvec</b>.</li> </ol><p>When the interrupt handler completes its task, the <code>mret</code> instruction is executed which will reverse this process. Control will be set to the address in <b>mepc</b>, and the value of <b>mstatus.MPIE</b> will be written to <b>mstatus.MIE</b> and cleared. The <b>mip</b> register will be cleared to indicate that there are no longer interrupts pending. Control flow will continue from where it was interrupted, and the core will be ready to handle new interrupts. More importantly, The hart will be returned to the privilege mode specified in the <b>mstatus.MPP</b> field. This behaviour can be exploited to set the current privilege mode of the processor.</p> </div> </div> <div class="outline-2" id="outline-container-orgd8dddb4"> <h2 id="orgd8dddb4">Enter the User</h2> <div class="outline-text-2" id="text-orgd8dddb4"> <p>The default privilege level when the processor is reset is machine mode. Programs running at this level have full control over the processor via the control and status registers. However, this opens up the system to abuse. To limit any damage that is possible by a wayward program, it is better to run in user mode. Getting to user mode is a simple matter of setting up the <b>mstatus</b> register and returning from M-mode via the <code>mret</code> instruction. The following macro will set the priviledge mode to the specified level:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="linenr"> 1: </span> # Set the privilege mode to that specified by the immediate <span class="linenr"> 2: </span> # value. <span class="linenr"> 3: </span> <span style="color: #00ffff;">.macro</span> setmode imm <span class="linenr"> 4: </span> <span style="color: #00ffff;">li</span> t0, 0x1800 #(ref:clear mstatus.MPP) <span class="coderef-off" id="coderef-load priv-mode"><span class="linenr"> 5: </span> <span style="color: #00ffff;">li</span> t0, \imm</span> <span class="coderef-off" id="coderef-create priv mask"><span class="linenr"> 6: </span> <span style="color: #00ffff;">slli</span> t0, t0, 11</span> <span class="linenr"> 7: </span> <span style="color: #00ffff;">csrrs</span> t0, mstatus, t0 #(ref:set mstatus.MPP) <span class="coderef-off" id="coderef-load return address"><span class="linenr"> 8: </span> <span style="color: #00ffff;">la</span> t0, 1f</span> <span class="coderef-off" id="coderef-set mepc"><span class="linenr"> 9: </span> <span style="color: #00ffff;">csrrw</span> zero, mepc, t0</span> <span class="linenr">10: </span> <span style="color: #00ffff;">mret</span> <span class="coderef-off" id="coderef-return location"><span class="linenr">11: </span><span style="color: #87cefa;">1</span>:</span> <span class="linenr">12: </span> <span style="color: #00ffff;">.endm</span> </pre></div> <p>This macro will set the privilege mode to the value specified as an immediate by first clearing the <b>mstatus.MPP</b> field on line <a class="coderef" href="#coderef-clear mstatus.MPP" onmouseout="CodeHighlightOff(this, 'coderef-clear mstatus.MPP');" onmouseover="CodeHighlightOn(this, 'coderef-clear mstatus.MPP');">4</a>, then replacing it with the encoding of the desired privilege mode. The following table lists the privilege modes and their encodings:</p> <table border="2" cellpadding="6" cellspacing="0" frame="hsides" rules="groups"><caption class="t-above"><span class="table-number">Table 2:</span> Privilege level encodings</caption> <colgroup><col class="org-left" /><col class="org-left" /><col class="org-left" /><col class="org-right" /></colgroup><thead><tr><th class="org-left" scope="col">Level</th> <th class="org-left" scope="col">Name</th> <th class="org-left" scope="col">Encoding</th> <th class="org-right" scope="col">Immediate</th> </tr></thead><tbody><tr><td class="org-left">U</td> <td class="org-left">User/Application</td> <td class="org-left">0b00</td> <td class="org-right">0</td> </tr><tr><td class="org-left">S</td> <td class="org-left">Supervisor</td> <td class="org-left">0b01</td> <td class="org-right">1</td> </tr><tr><td class="org-left">M</td> <td class="org-left">Machine</td> <td class="org-left">0b11</td> <td class="org-right">3</td> </tr></tbody></table><p>The fourth column of this table lists the immediate value that should be supplied to the macro to set the associated privilege mode. The encoded privilege value is loaded into register <b>t0</b> on line <a class="coderef" href="#coderef-load priv-mode" onmouseout="CodeHighlightOff(this, 'coderef-load priv-mode');" onmouseover="CodeHighlightOn(this, 'coderef-load priv-mode');">5</a>, then shifted to the right position on the next line. This field is set via the <code>csrrs</code> instruction on line <a class="coderef" href="#coderef-set mstatus.MPP" onmouseout="CodeHighlightOff(this, 'coderef-set mstatus.MPP');" onmouseover="CodeHighlightOn(this, 'coderef-set mstatus.MPP');">7</a> which effectively sets <b>mstatus</b> to the bit-wise <b>OR</b> of its previous value with the value in <b>t0</b>. However, before returning from machine-mode, the <b>mepc</b> register must be updated with the address of the instruction to which control will return.</p> <p>The address immediately following the <code>mret</code> instruction is loaded into register <b>t0</b> on line <a class="coderef" href="#coderef-load return address" onmouseout="CodeHighlightOff(this, 'coderef-load return address');" onmouseover="CodeHighlightOn(this, 'coderef-load return address');">8</a>, then written to <b>mepc</b> on line <a class="coderef" href="#coderef-set mepc" onmouseout="CodeHighlightOff(this, 'coderef-set mepc');" onmouseover="CodeHighlightOn(this, 'coderef-set mepc');">9</a>. When the <code>mret</code> instruction is executed, <b>pc</b> will be set to this address. If the main program is updated to invoke this macro with the argument 0 just before the <code>wfi</code>, the program should be in U-mode by the time the timer expires:</p> <div class="org-src-container"> <pre class="src src-asm" id="org6f4fee5"> <span class="linenr">26: </span><span style="color: #87cefa;">1</span>: <span style="color: #00ffff;">li</span> a0, 0x10000 # Set the timeout value <span class="linenr">27: </span> <span style="color: #00ffff;">call</span> __timer_create # Set the timer <span class="coderef-off" id="coderef-set U-mode"><span class="linenr">28: </span> <span style="color: #00ffff;">setmode</span> 0</span> <span class="linenr">29: </span> <span style="color: #00ffff;">wfi</span> <span class="linenr">30: </span> <span style="color: #00ffff;">j</span> 1b <span class="linenr">31: </span> </pre></div> <p>Anything that runs following the call to the <code>setmode</code> macro will be executing in U-mode. However, the trap handler will execute in machine mode. Therefore the trap handler is useful for performing tasks that require machine mode privilege. Fortunately, traps can occur for asynchronous interrupts as well as synchronous exceptions. Therefore the trap handler can be used to implement system calls.</p> <p>The <code>ecall</code> instruction is an environment call which raises a synchronous exception, and sets <b>mcause</b> to the code indicating the active privilege mode when it was executed. The trap handler can be updated to jump to the appropriate function, which will execute in machine mode, then returning to the original pivilege mode when it is complete. The trap handler must be updated to handle the system call:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="linenr"> 1: </span> <span style="color: #00ffff;">.align</span> 2 <span class="linenr"> 2: </span><span style="color: #87cefa;">__mtrap_handler</span>: <span class="linenr"> 3: </span> <span style="color: #00ffff;">csrr</span> t0, mcause <span class="coderef-off" id="coderef-Check for exception"><span class="linenr"> 4: </span> <span style="color: #00ffff;">bgez</span> t0, 1f</span> <span class="linenr"> 5: </span> <span style="color: #00ffff;">slli</span> t0, t0, 1 <span class="linenr"> 6: </span> <span style="color: #00ffff;">srli</span> t0, t0, 1 <span class="coderef-off" id="coderef-Timer interrupt code"><span class="linenr"> 7: </span> <span style="color: #00ffff;">li</span> t1, 7</span> <span class="linenr"> 8: </span> <span style="color: #00ffff;">bne</span> t0, t1, 2f <span class="coderef-off" id="coderef-Increment interrupt count"><span class="linenr"> 9: </span> <span style="color: #00ffff;">addi</span> s0, s0, 1</span> <span class="linenr">10: </span> <span style="color: #00ffff;">j</span> 2f <span class="linenr">11: </span><span style="color: #87cefa;">1</span>: <span class="coderef-off" id="coderef-U-mode ecall code"><span class="linenr">12: </span> <span style="color: #00ffff;">li</span> t1, 8</span> <span class="linenr">13: </span> <span style="color: #00ffff;">bne</span> t0, t1, 2f <span class="coderef-off" id="coderef-save registers"><span class="linenr">14: </span> <span style="color: #00ffff;">push_stack</span></span> <span class="linenr">15: </span> <span style="color: #00ffff;">call</span> __syscall <span class="coderef-off" id="coderef-restore registers"><span class="linenr">16: </span> <span style="color: #00ffff;">pop_stack</span></span> <span class="coderef-off" id="coderef-Load mret address"><span class="linenr">17: </span> <span style="color: #00ffff;">csrr</span> t0, mepc</span> <span class="coderef-off" id="coderef-Set mret address"><span class="linenr">18: </span> <span style="color: #00ffff;">addi</span> t0, t0, 4</span> <span class="linenr">19: </span> <span style="color: #00ffff;">csrrw</span> zero, mepc, t0 <span class="linenr">20: </span><span style="color: #87cefa;">2</span>: <span style="color: #00ffff;">csrrw</span> t0, mcause, zero <span class="coderef-off" id="coderef-Machine trap return"><span class="linenr">21: </span> <span style="color: #00ffff;">mret</span></span> <span class="linenr">22: </span> </pre></div> <p>This handler is updated by adding some code for synchronous exceptions (starting at line <a class="coderef" href="#coderef-U-mode ecall code" onmouseout="CodeHighlightOff(this, 'coderef-U-mode ecall code');" onmouseover="CodeHighlightOn(this, 'coderef-U-mode ecall code');">12</a>). The value of <b>mcause</b> is compared with the user-environment call exception code (8) to see if a system call was requested. If so, the handler will save the registers on the stack via the <code>push_stack</code> macro on line <a class="coderef" href="#coderef-save registers" onmouseout="CodeHighlightOff(this, 'coderef-save registers');" onmouseover="CodeHighlightOn(this, 'coderef-save registers');">14</a>, call the <code>__syscall</code> function, then resture the registers to their values prior to the call via the <code>pop_stack</code> macro on line <a class="coderef" href="#coderef-restore registers" onmouseout="CodeHighlightOff(this, 'coderef-restore registers');" onmouseover="CodeHighlightOn(this, 'coderef-restore registers');">16</a>.</p> <p>After the system call has finished processing, the handler loads the value of the <b>mepc</b> CSR which should contain the address of the <code>ecall</code> instruction that caused the trap. This address is incremented by 4 to skip to the instruction that follows <code>ecall</code> on line <a class="coderef" href="#coderef-Set mret address" onmouseout="CodeHighlightOff(this, 'coderef-Set mret address');" onmouseover="CodeHighlightOn(this, 'coderef-Set mret address');">18</a>, then stores the updated address in <b>mepc</b> before executing <code>mret</code>. This will set the program counter to the instruction immediately following the one that triggered the system call, and restore the privilege mode to U-mode.</p> <p>Typically system calls are identified by a number. If its arguments are stored in the registers <b>a0</b> to <b>a7</b>, and its return value in <b>a0</b>, system calls will follow the same convention as regular function calls (albeit with greater privilege). The following code snippet will invoke the system call associated with the identifier 0x100:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="coderef-off" id="coderef-load syscall id"><span class="linenr">1: </span><span style="color: #87cefa;">li</span> <span style="color: #00ffff;">a0</span>, 0x100</span> <span class="coderef-off" id="coderef-execute the syscall"><span class="linenr">2: </span><span style="color: #87cefa;">ecall</span></span> </pre></div> <p>The timer can now be set from user mode via a system call. The following implementation of <code>__syscall</code> will invoke <code>__timer_create</code> with the timeout value specified in register <b>a1</b> when system call 0x100 is requested:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="linenr"> 1: </span><span style="color: #87cefa;">__syscall</span>: <span class="linenr"> 2: </span> <span style="color: #00ffff;">mv</span> s1, a0 <span class="coderef-off" id="coderef-timer syscall"><span class="linenr"> 3: </span> <span style="color: #00ffff;">li</span> t0, 0x100</span> <span class="linenr"> 4: </span> <span style="color: #00ffff;">bne</span> t0, a0, 1f <span class="coderef-off" id="coderef-set timeout arg"><span class="linenr"> 5: </span> <span style="color: #00ffff;">mv</span> a0, a1</span> <span class="linenr"> 6: </span> <span style="color: #00ffff;">push_stack</span> <span class="linenr"> 7: </span> <span style="color: #00ffff;">call</span> __timer_create <span class="linenr"> 8: </span> <span style="color: #00ffff;">pop_stack</span> <span class="linenr"> 9: </span><span style="color: #87cefa;">1</span>: <span style="color: #00ffff;">ret</span> <span class="linenr">10: </span> </pre></div> <p>This function will check the register <b>a0</b> to determine the system call id that is requested. If it is 0x100, then it will move the timeout value from register <b>a1</b> to <b>a0</b> on line <a class="coderef" href="#coderef-set timeout arg" onmouseout="CodeHighlightOff(this, 'coderef-set timeout arg');" onmouseover="CodeHighlightOn(this, 'coderef-set timeout arg');">5</a>, push the stack, then invoke the <code>__timer_create</code> function with M-mode privilege. The main program can be updated to set the privilege level to U-mode, then make a system call 0x100 to set the timer. The updated main program is illustrated in the following listing:</p> <div class="org-src-container"> <pre class="src src-asm"> <span class="linenr"> 1: </span> <span style="color: #00ffff;">.section</span> <span style="color: #ffa07a;">".text.init"</span> <span class="linenr"> 2: </span> <span style="color: #00ffff;">.align</span> 2 <span class="linenr"> 3: </span> <span style="color: #00ffff;">.global</span> _stack_end <span class="linenr"> 4: </span> <span style="color: #00ffff;">.global</span> CLOCK_MONOTONIC <span class="linenr"> 5: </span> <span style="color: #00ffff;">.global</span> _start <span class="linenr"> 6: </span><span style="color: #87cefa;">_start</span>: <span class="linenr"> 7: </span> <span style="color: #00ffff;">la</span> sp, _stack_end <span class="linenr"> 8: </span> <span style="color: #00ffff;">call</span> __system_check <span class="linenr"> 9: </span> <span style="color: #00ffff;">la</span> t0, __mtrap_handler <span class="linenr">10: </span> <span style="color: #00ffff;">csrrw</span> zero, mtvec, t0 <span class="linenr">11: </span> <span style="color: #00ffff;">li</span> t0, 0b1&lt;&lt;3 <span class="linenr">12: </span> <span style="color: #00ffff;">csrrs</span> zero, mstatus, t0 <span class="linenr">13: </span> <span style="color: #00ffff;">li</span> t0, 0b1&lt;&lt;7 <span class="linenr">14: </span> <span style="color: #00ffff;">csrrs</span> zero, mie, t0 <span class="linenr">15: </span> <span style="color: #00ffff;">setmode</span> 0 <span class="coderef-off" id="coderef-set timer syscall"><span class="linenr">16: </span><span style="color: #87cefa;">1</span>: <span style="color: #00ffff;">li</span> a0, 0x100</span> <span class="coderef-off" id="coderef-set system timeout"><span class="linenr">17: </span> <span style="color: #00ffff;">li</span> a1, 0x10000</span> <span class="linenr">18: </span> <span style="color: #00ffff;">ecall</span> <span class="linenr">19: </span> <span style="color: #00ffff;">wfi</span> <span class="linenr">20: </span> <span style="color: #00ffff;">j</span> 1b </pre></div> <p>The major difference from the previous main program is that the timer is not set directly, but via a system call. The syscall id is loaded into register <b>a0</b> on line <a class="coderef" href="#coderef-set timer syscall" onmouseout="CodeHighlightOff(this, 'coderef-set timer syscall');" onmouseover="CodeHighlightOn(this, 'coderef-set timer syscall');">16</a>, and the timeout value into register <b>a1</b> on line <a class="coderef" href="#coderef-set system timeout" onmouseout="CodeHighlightOff(this, 'coderef-set system timeout');" onmouseover="CodeHighlightOn(this, 'coderef-set system timeout');">17</a>. This set of instructions will be repeated each time a timeout is triggered.</p> </div> </div> <div class="outline-2" id="outline-container-orgdb17f69"> <h2 id="orgdb17f69">Conclusion</h2> <div class="outline-text-2" id="text-orgdb17f69"> <p>This chapter has delved into how RISC-V handles synchronous and asynchronous exceptions as well as the privilege mode instructions available in the ISA. This may be one of the key components in the development of an operating system by allowing privileged functions to run separately from user code. System calls allow U-mode applications to request services which require M-mode (or S-mode) privilege to execute via the <code>ecall</code> instruction.</p> <p>Moreover, the asynchronous exception handling provides a good introduction into how RISC-V processors deal with events originating from external peripherals. This will become important when creating programs intended to interact with the system user.</p> <p>Although the examples in this chapter were restricted to M-mode and U-mode privilege levels. The supervisor mode was briefly discussed. Having three privilege levels is useful when creating hypervisors: guest operating systems can operate in S-mode while the virtualization environment uses M-mode.</p> <p>The next chapter will leverage many of the capabilities discussed here to interface with more of the external components in a RISC-V system. In particular the UART module will allow users to interact with applications via a serial console.</p> </div> </div> </div> </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/main/user/1" lang="" about="/main/user/1" typeof="schema:Person" property="schema:name" datatype="" class="username">MarcAdmin</a></span> <span property="dc:date dc:created" content="2019-12-11T02:36:21+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">Tue, 12/10/2019 - 21:36</span> <div class="field field--name-field-tags field--type-entity-reference field--label-above clearfix"> <h3 class="field__label">Tags</h3> <ul class="links field__items"> <li><a href="/main/riscv" rel="dc:subject" hreflang="en">RISC-V</a></li> <li><a href="/main/taxonomy/term/17" rel="dc:subject" hreflang="en">Computer Architecture</a></li> </ul> </div> Wed, 11 Dec 2019 02:36:21 +0000 MarcAdmin 35 at