1# Copyright (c) 2008 The Regents of The University of Michigan 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are 6# met: redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer; 8# redistributions in binary form must reproduce the above copyright 9# notice, this list of conditions and the following disclaimer in the 10# documentation and/or other materials provided with the distribution; 11# neither the name of the copyright holders nor the names of its 12# contributors may be used to endorse or promote products derived from 13# this software without specific prior written permission. 14# 15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26# 27# Authors: Gabe Black 28 29intCodeTemplate = ''' 30def rom 31{ 32 # This vectors the CPU into an interrupt handler in long mode. 33 # On entry, t1 is set to the vector of the interrupt and t7 is the current 34 # ip. We need that because rdip returns the next ip. 35 extern %(startLabel)s: 36 37 # 38 # Get the 64 bit interrupt or trap gate descriptor from the IDT 39 # 40 41 # Load the gate descriptor from the IDT 42 slli t4, t1, 4, dataSize=8 43 ld t2, idtr, [1, t0, t4], 8, dataSize=8, addressSize=8, atCPL0=True 44 ld t4, idtr, [1, t0, t4], dataSize=8, addressSize=8, atCPL0=True 45 46 # Make sure the descriptor is a legal gate. 47 chks t1, t4, %(gateCheckType)s 48 49 # 50 # Get the target CS descriptor using the selector in the gate 51 # descriptor. 52 # 53 srli t10, t4, 16, dataSize=8 54 andi t5, t10, 0xF8, dataSize=8 55 andi t0, t10, 0x4, flags=(EZF,), dataSize=2 56 br rom_local_label("%(startLabel)s_globalDescriptor"), flags=(CEZF,) 57 ld t3, tsl, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True 58 br rom_local_label("%(startLabel)s_processDescriptor") 59%(startLabel)s_globalDescriptor: 60 ld t3, tsg, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True 61%(startLabel)s_processDescriptor: 62 chks t10, t3, IntCSCheck, dataSize=8 63 wrdl hs, t3, t10, dataSize=8 64 65 # Stick the target offset in t9. 66 wrdh t9, t4, t2, dataSize=8 67 68 69 # 70 # Figure out where the stack should be 71 # 72 73 # Record what we might set the stack selector to. 74 rdsel t11, ss 75 76 # Check if we're changing privelege level. At this point we can assume 77 # we're going to a DPL that's less than or equal to the CPL. 78 rdattr t10, hs, dataSize=8 79 andi t10, t10, 3, dataSize=8 80 rdattr t5, cs, dataSize=8 81 andi t5, t5, 0x3, dataSize=8 82 sub t0, t5, t10, flags=(EZF,), dataSize=8 83 # We're going to change priviledge, so zero out the stack selector. We 84 # need to let the IST have priority so we don't branch yet. 85 mov t11, t0, t0, flags=(nCEZF,) 86 87 # Check the IST field of the gate descriptor 88 srli t12, t4, 32, dataSize=8 89 andi t12, t12, 0x7, dataSize=8 90 subi t0, t12, 1, flags=(ECF,), dataSize=8 91 br rom_local_label("%(startLabel)s_istStackSwitch"), flags=(nCECF,) 92 br rom_local_label("%(startLabel)s_cplStackSwitch"), flags=(nCEZF,) 93 94 # If we're here, it's because the stack isn't being switched. 95 # Set t6 to the new aligned rsp. 96 mov t6, t6, rsp, dataSize=8 97 br rom_local_label("%(startLabel)s_stackSwitched") 98 99%(startLabel)s_istStackSwitch: 100 ld t6, tr, [8, t12, t0], 0x1c, dataSize=8, addressSize=8, atCPL0=True 101 br rom_local_label("%(startLabel)s_stackSwitched") 102 103%(startLabel)s_cplStackSwitch: 104 # Get the new rsp from the TSS 105 ld t6, tr, [8, t10, t0], 4, dataSize=8, addressSize=8, atCPL0=True 106 107%(startLabel)s_stackSwitched: 108 109 andi t6, t6, 0xF0, dataSize=1 110 subi t6, t6, 40 + %(errorCodeSize)d, dataSize=8 111 112 ## 113 ## Point of no return. 114 ## We're now going to irrevocably modify visible state. 115 ## Anything bad that's going to happen should have happened by now or will 116 ## happen right now. 117 ## 118 wrip t0, t9, dataSize=8 119 120 # 121 # Set up the target code segment. Do this now so we have the right 122 # permissions when setting up the stack frame. 123 # 124 srli t5, t4, 16, dataSize=8 125 andi t5, t5, 0xFF, dataSize=8 126 wrdl cs, t3, t5, dataSize=8 127 # Tuck away the old CS for use below 128 limm t10, 0, dataSize=8 129 rdsel t10, cs, dataSize=2 130 wrsel cs, t5, dataSize=2 131 132 # Check that we can access everything we need to on the stack 133 ldst t0, hs, [1, t0, t6], dataSize=8, addressSize=8 134 ldst t0, hs, [1, t0, t6], \ 135 32 + %(errorCodeSize)d, dataSize=8, addressSize=8 136 137 138 # 139 # Build up the interrupt stack frame 140 # 141 142 143 # Write out the contents of memory 144 %(errorCodeCode)s 145 st t7, hs, [1, t0, t6], %(errorCodeSize)d, dataSize=8, addressSize=8 146 st t10, hs, [1, t0, t6], 8 + %(errorCodeSize)d, dataSize=8, addressSize=8 147 rflags t10, dataSize=8 148 st t10, hs, [1, t0, t6], 16 + %(errorCodeSize)d, dataSize=8, addressSize=8 149 st rsp, hs, [1, t0, t6], 24 + %(errorCodeSize)d, dataSize=8, addressSize=8 150 rdsel t5, ss, dataSize=2 151 st t5, hs, [1, t0, t6], 32 + %(errorCodeSize)d, dataSize=8, addressSize=8 152 153 # Set the stack segment 154 mov rsp, rsp, t6, dataSize=8 155 wrsel ss, t11, dataSize=2 156 157 # 158 # Adjust rflags which is still in t10 from above 159 # 160 161 # Set IF to the lowest bit of the original gate type. 162 # The type field of the original gate starts at bit 40. 163 164 # Set the TF, NT, and RF bits. We'll flip them at the end. 165 limm t6, (1 << 8) | (1 << 14) | (1 << 16), dataSize=8 166 or t10, t10, t6, dataSize=8 167 srli t5, t4, 40, dataSize=8 168 srli t7, t10, 9, dataSize=8 169 xor t5, t7, t5, dataSize=8 170 andi t5, t5, 1, dataSize=8 171 slli t5, t5, 9, dataSize=8 172 or t6, t5, t6, dataSize=8 173 174 # Put the results into rflags 175 wrflags t6, t10 176 177 eret 178}; 179''' 180 181microcode = \ 182intCodeTemplate % {\ 183 "startLabel" : "longModeInterrupt", 184 "gateCheckType" : "IntGateCheck", 185 "errorCodeSize" : 0, 186 "errorCodeCode" : "" 187} + \ 188intCodeTemplate % {\ 189 "startLabel" : "longModeSoftInterrupt", 190 "gateCheckType" : "SoftIntGateCheck", 191 "errorCodeSize" : 0, 192 "errorCodeCode" : "" 193} + \ 194intCodeTemplate % {\ 195 "startLabel" : "longModeInterruptWithError", 196 "gateCheckType" : "IntGateCheck", 197 "errorCodeSize" : 8, 198 "errorCodeCode" : ''' 199 st t15, hs, [1, t0, t6], dataSize=8, addressSize=8 200 ''' 201} + \ 202''' 203def rom 204{ 205 # This vectors the CPU into an interrupt handler in legacy mode. 206 extern legacyModeInterrupt: 207 panic "Legacy mode interrupts not implemented (in microcode)" 208 eret 209}; 210 211def rom 212{ 213 extern initIntHalt: 214 rflags t1 215 limm t2, "~IFBit" 216 and t1, t1, t2 217 wrflags t1, t0 218 halt 219 eret 220}; 221''' 222