interrupts.cc revision 5648
1/* 2 * Copyright (c) 2008 The Hewlett-Packard Development Company 3 * All rights reserved. 4 * 5 * Redistribution and use of this software in source and binary forms, 6 * with or without modification, are permitted provided that the 7 * following conditions are met: 8 * 9 * The software must be used only for Non-Commercial Use which means any 10 * use which is NOT directed to receiving any direct monetary 11 * compensation for, or commercial advantage from such use. Illustrative 12 * examples of non-commercial use are academic research, personal study, 13 * teaching, education and corporate research & development. 14 * Illustrative examples of commercial use are distributing products for 15 * commercial advantage and providing services using the software for 16 * commercial advantage. 17 * 18 * If you wish to use this software or functionality therein that may be 19 * covered by patents for commercial use, please contact: 20 * Director of Intellectual Property Licensing 21 * Office of Strategy and Technology 22 * Hewlett-Packard Company 23 * 1501 Page Mill Road 24 * Palo Alto, California 94304 25 * 26 * Redistributions of source code must retain the above copyright notice, 27 * this list of conditions and the following disclaimer. Redistributions 28 * in binary form must reproduce the above copyright notice, this list of 29 * conditions and the following disclaimer in the documentation and/or 30 * other materials provided with the distribution. Neither the name of 31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its 32 * contributors may be used to endorse or promote products derived from 33 * this software without specific prior written permission. No right of 34 * sublicense is granted herewith. Derivatives of the software and 35 * output created using the software may be prepared, but only for 36 * Non-Commercial Uses. Derivatives of the software may be shared with 37 * others provided: (i) the others agree to abide by the list of 38 * conditions herein which includes the Non-Commercial Use restrictions; 39 * and (ii) such Derivatives of the software include the above copyright 40 * notice to acknowledge the contribution from this software where 41 * applicable, this list of conditions and the disclaimer below. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 * 55 * Authors: Gabe Black 56 */ 57 58#include "arch/x86/apicregs.hh" 59#include "arch/x86/interrupts.hh" 60#include "cpu/base.hh" 61 62int 63divideFromConf(uint32_t conf) 64{ 65 // This figures out what division we want from the division configuration 66 // register in the local APIC. The encoding is a little odd but it can 67 // be deciphered fairly easily. 68 int shift = ((conf & 0x8) >> 1) | (conf & 0x3); 69 shift = (shift + 1) % 8; 70 return 1 << shift; 71} 72 73namespace X86ISA 74{ 75 76ApicRegIndex 77decodeAddr(Addr paddr) 78{ 79 ApicRegIndex regNum; 80 paddr &= ~mask(3); 81 switch (paddr) 82 { 83 case 0x20: 84 regNum = APIC_ID; 85 break; 86 case 0x30: 87 regNum = APIC_VERSION; 88 break; 89 case 0x80: 90 regNum = APIC_TASK_PRIORITY; 91 break; 92 case 0x90: 93 regNum = APIC_ARBITRATION_PRIORITY; 94 break; 95 case 0xA0: 96 regNum = APIC_PROCESSOR_PRIORITY; 97 break; 98 case 0xB0: 99 regNum = APIC_EOI; 100 break; 101 case 0xD0: 102 regNum = APIC_LOGICAL_DESTINATION; 103 break; 104 case 0xE0: 105 regNum = APIC_DESTINATION_FORMAT; 106 break; 107 case 0xF0: 108 regNum = APIC_SPURIOUS_INTERRUPT_VECTOR; 109 break; 110 case 0x100: 111 case 0x108: 112 case 0x110: 113 case 0x118: 114 case 0x120: 115 case 0x128: 116 case 0x130: 117 case 0x138: 118 case 0x140: 119 case 0x148: 120 case 0x150: 121 case 0x158: 122 case 0x160: 123 case 0x168: 124 case 0x170: 125 case 0x178: 126 regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8); 127 break; 128 case 0x180: 129 case 0x188: 130 case 0x190: 131 case 0x198: 132 case 0x1A0: 133 case 0x1A8: 134 case 0x1B0: 135 case 0x1B8: 136 case 0x1C0: 137 case 0x1C8: 138 case 0x1D0: 139 case 0x1D8: 140 case 0x1E0: 141 case 0x1E8: 142 case 0x1F0: 143 case 0x1F8: 144 regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8); 145 break; 146 case 0x200: 147 case 0x208: 148 case 0x210: 149 case 0x218: 150 case 0x220: 151 case 0x228: 152 case 0x230: 153 case 0x238: 154 case 0x240: 155 case 0x248: 156 case 0x250: 157 case 0x258: 158 case 0x260: 159 case 0x268: 160 case 0x270: 161 case 0x278: 162 regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8); 163 break; 164 case 0x280: 165 regNum = APIC_ERROR_STATUS; 166 break; 167 case 0x300: 168 regNum = APIC_INTERRUPT_COMMAND_LOW; 169 break; 170 case 0x310: 171 regNum = APIC_INTERRUPT_COMMAND_HIGH; 172 break; 173 case 0x320: 174 regNum = APIC_LVT_TIMER; 175 break; 176 case 0x330: 177 regNum = APIC_LVT_THERMAL_SENSOR; 178 break; 179 case 0x340: 180 regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS; 181 break; 182 case 0x350: 183 regNum = APIC_LVT_LINT0; 184 break; 185 case 0x360: 186 regNum = APIC_LVT_LINT1; 187 break; 188 case 0x370: 189 regNum = APIC_LVT_ERROR; 190 break; 191 case 0x380: 192 regNum = APIC_INITIAL_COUNT; 193 break; 194 case 0x390: 195 regNum = APIC_CURRENT_COUNT; 196 break; 197 case 0x3E0: 198 regNum = APIC_DIVIDE_CONFIGURATION; 199 break; 200 default: 201 // A reserved register field. 202 panic("Accessed reserved register field %#x.\n", paddr); 203 break; 204 } 205 return regNum; 206} 207} 208 209Tick 210X86ISA::Interrupts::read(PacketPtr pkt) 211{ 212 Addr offset = pkt->getAddr() - pioAddr; 213 //Make sure we're at least only accessing one register. 214 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) 215 panic("Accessed more than one register at a time in the APIC!\n"); 216 ApicRegIndex reg = decodeAddr(offset); 217 uint32_t val = htog(readReg(reg)); 218 pkt->setData(((uint8_t *)&val) + (offset & mask(3))); 219 return latency; 220} 221 222Tick 223X86ISA::Interrupts::write(PacketPtr pkt) 224{ 225 Addr offset = pkt->getAddr() - pioAddr; 226 //Make sure we're at least only accessing one register. 227 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) 228 panic("Accessed more than one register at a time in the APIC!\n"); 229 ApicRegIndex reg = decodeAddr(offset); 230 uint32_t val = regs[reg]; 231 pkt->writeData(((uint8_t *)&val) + (offset & mask(3))); 232 setReg(reg, gtoh(val)); 233 return latency; 234} 235 236uint32_t 237X86ISA::Interrupts::readReg(ApicRegIndex reg) 238{ 239 if (reg >= APIC_TRIGGER_MODE(0) && 240 reg <= APIC_TRIGGER_MODE(15)) { 241 panic("Local APIC Trigger Mode registers are unimplemented.\n"); 242 } 243 switch (reg) { 244 case APIC_ARBITRATION_PRIORITY: 245 panic("Local APIC Arbitration Priority register unimplemented.\n"); 246 break; 247 case APIC_PROCESSOR_PRIORITY: 248 panic("Local APIC Processor Priority register unimplemented.\n"); 249 break; 250 case APIC_EOI: 251 panic("Local APIC EOI register unimplemented.\n"); 252 break; 253 case APIC_ERROR_STATUS: 254 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); 255 break; 256 case APIC_INTERRUPT_COMMAND_LOW: 257 panic("Local APIC Interrupt Command low" 258 " register unimplemented.\n"); 259 break; 260 case APIC_INTERRUPT_COMMAND_HIGH: 261 panic("Local APIC Interrupt Command high" 262 " register unimplemented.\n"); 263 break; 264 case APIC_CURRENT_COUNT: 265 { 266 assert(clock); 267 uint32_t val = regs[reg] - curTick / clock; 268 val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); 269 return val; 270 } 271 default: 272 break; 273 } 274 return regs[reg]; 275} 276 277void 278X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) 279{ 280 uint32_t newVal = val; 281 if (reg >= APIC_IN_SERVICE(0) && 282 reg <= APIC_IN_SERVICE(15)) { 283 panic("Local APIC In-Service registers are unimplemented.\n"); 284 } 285 if (reg >= APIC_TRIGGER_MODE(0) && 286 reg <= APIC_TRIGGER_MODE(15)) { 287 panic("Local APIC Trigger Mode registers are unimplemented.\n"); 288 } 289 if (reg >= APIC_INTERRUPT_REQUEST(0) && 290 reg <= APIC_INTERRUPT_REQUEST(15)) { 291 panic("Local APIC Interrupt Request registers " 292 "are unimplemented.\n"); 293 } 294 switch (reg) { 295 case APIC_ID: 296 newVal = val & 0xFF; 297 break; 298 case APIC_VERSION: 299 // The Local APIC Version register is read only. 300 return; 301 case APIC_TASK_PRIORITY: 302 newVal = val & 0xFF; 303 break; 304 case APIC_ARBITRATION_PRIORITY: 305 panic("Local APIC Arbitration Priority register unimplemented.\n"); 306 break; 307 case APIC_PROCESSOR_PRIORITY: 308 panic("Local APIC Processor Priority register unimplemented.\n"); 309 break; 310 case APIC_EOI: 311 panic("Local APIC EOI register unimplemented.\n"); 312 break; 313 case APIC_LOGICAL_DESTINATION: 314 newVal = val & 0xFF000000; 315 break; 316 case APIC_DESTINATION_FORMAT: 317 newVal = val | 0x0FFFFFFF; 318 break; 319 case APIC_SPURIOUS_INTERRUPT_VECTOR: 320 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1); 321 regs[APIC_INTERNAL_STATE] |= val & (1 << 8); 322 if (val & (1 << 9)) 323 warn("Focus processor checking not implemented.\n"); 324 break; 325 case APIC_ERROR_STATUS: 326 { 327 if (regs[APIC_INTERNAL_STATE] & 0x1) { 328 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); 329 newVal = 0; 330 } else { 331 regs[APIC_INTERNAL_STATE] |= ULL(0x1); 332 return; 333 } 334 335 } 336 break; 337 case APIC_INTERRUPT_COMMAND_LOW: 338 panic("Local APIC Interrupt Command low" 339 " register unimplemented.\n"); 340 break; 341 case APIC_INTERRUPT_COMMAND_HIGH: 342 panic("Local APIC Interrupt Command high" 343 " register unimplemented.\n"); 344 break; 345 case APIC_LVT_TIMER: 346 case APIC_LVT_THERMAL_SENSOR: 347 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: 348 case APIC_LVT_LINT0: 349 case APIC_LVT_LINT1: 350 case APIC_LVT_ERROR: 351 { 352 uint64_t readOnlyMask = (1 << 12) | (1 << 14); 353 newVal = (val & ~readOnlyMask) | 354 (regs[reg] & readOnlyMask); 355 } 356 break; 357 case APIC_INITIAL_COUNT: 358 { 359 assert(clock); 360 newVal = bits(val, 31, 0); 361 uint32_t newCount = newVal * 362 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16); 363 regs[APIC_CURRENT_COUNT] = newCount + curTick / clock; 364 // Find out how long a "tick" of the timer should take. 365 Tick timerTick = 16 * clock; 366 // Schedule on the edge of the next tick plus the new count. 367 Tick offset = curTick % timerTick; 368 if (offset) { 369 reschedule(apicTimerEvent, 370 curTick + (newCount + 1) * timerTick - offset, true); 371 } else { 372 reschedule(apicTimerEvent, 373 curTick + newCount * timerTick, true); 374 } 375 } 376 break; 377 case APIC_CURRENT_COUNT: 378 //Local APIC Current Count register is read only. 379 return; 380 case APIC_DIVIDE_CONFIGURATION: 381 newVal = val & 0xB; 382 break; 383 default: 384 break; 385 } 386 regs[reg] = newVal; 387 return; 388} 389 390X86ISA::Interrupts * 391X86LocalApicParams::create() 392{ 393 return new X86ISA::Interrupts(this); 394} 395