interrupts.cc revision 5649
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 DPRINTF(LocalApic, 219 "Reading Local APIC register %d at offset %#x as %#x.\n", 220 reg, offset, val); 221 pkt->setData(((uint8_t *)&val) + (offset & mask(3))); 222 return latency; 223} 224 225Tick 226X86ISA::Interrupts::write(PacketPtr pkt) 227{ 228 Addr offset = pkt->getAddr() - pioAddr; 229 //Make sure we're at least only accessing one register. 230 if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3))) 231 panic("Accessed more than one register at a time in the APIC!\n"); 232 ApicRegIndex reg = decodeAddr(offset); 233 uint32_t val = regs[reg]; 234 pkt->writeData(((uint8_t *)&val) + (offset & mask(3))); 235 DPRINTF(LocalApic, 236 "Writing Local APIC register %d at offset %#x as %#x.\n", 237 reg, offset, gtoh(val)); 238 setReg(reg, gtoh(val)); 239 return latency; 240} 241 242uint32_t 243X86ISA::Interrupts::readReg(ApicRegIndex reg) 244{ 245 if (reg >= APIC_TRIGGER_MODE(0) && 246 reg <= APIC_TRIGGER_MODE(15)) { 247 panic("Local APIC Trigger Mode registers are unimplemented.\n"); 248 } 249 switch (reg) { 250 case APIC_ARBITRATION_PRIORITY: 251 panic("Local APIC Arbitration Priority register unimplemented.\n"); 252 break; 253 case APIC_PROCESSOR_PRIORITY: 254 panic("Local APIC Processor Priority register unimplemented.\n"); 255 break; 256 case APIC_EOI: 257 panic("Local APIC EOI register unimplemented.\n"); 258 break; 259 case APIC_ERROR_STATUS: 260 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); 261 break; 262 case APIC_INTERRUPT_COMMAND_LOW: 263 panic("Local APIC Interrupt Command low" 264 " register unimplemented.\n"); 265 break; 266 case APIC_INTERRUPT_COMMAND_HIGH: 267 panic("Local APIC Interrupt Command high" 268 " register unimplemented.\n"); 269 break; 270 case APIC_CURRENT_COUNT: 271 { 272 assert(clock); 273 uint32_t val = regs[reg] - curTick / clock; 274 val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])); 275 return val; 276 } 277 default: 278 break; 279 } 280 return regs[reg]; 281} 282 283void 284X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val) 285{ 286 uint32_t newVal = val; 287 if (reg >= APIC_IN_SERVICE(0) && 288 reg <= APIC_IN_SERVICE(15)) { 289 panic("Local APIC In-Service registers are unimplemented.\n"); 290 } 291 if (reg >= APIC_TRIGGER_MODE(0) && 292 reg <= APIC_TRIGGER_MODE(15)) { 293 panic("Local APIC Trigger Mode registers are unimplemented.\n"); 294 } 295 if (reg >= APIC_INTERRUPT_REQUEST(0) && 296 reg <= APIC_INTERRUPT_REQUEST(15)) { 297 panic("Local APIC Interrupt Request registers " 298 "are unimplemented.\n"); 299 } 300 switch (reg) { 301 case APIC_ID: 302 newVal = val & 0xFF; 303 break; 304 case APIC_VERSION: 305 // The Local APIC Version register is read only. 306 return; 307 case APIC_TASK_PRIORITY: 308 newVal = val & 0xFF; 309 break; 310 case APIC_ARBITRATION_PRIORITY: 311 panic("Local APIC Arbitration Priority register unimplemented.\n"); 312 break; 313 case APIC_PROCESSOR_PRIORITY: 314 panic("Local APIC Processor Priority register unimplemented.\n"); 315 break; 316 case APIC_EOI: 317 panic("Local APIC EOI register unimplemented.\n"); 318 break; 319 case APIC_LOGICAL_DESTINATION: 320 newVal = val & 0xFF000000; 321 break; 322 case APIC_DESTINATION_FORMAT: 323 newVal = val | 0x0FFFFFFF; 324 break; 325 case APIC_SPURIOUS_INTERRUPT_VECTOR: 326 regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1); 327 regs[APIC_INTERNAL_STATE] |= val & (1 << 8); 328 if (val & (1 << 9)) 329 warn("Focus processor checking not implemented.\n"); 330 break; 331 case APIC_ERROR_STATUS: 332 { 333 if (regs[APIC_INTERNAL_STATE] & 0x1) { 334 regs[APIC_INTERNAL_STATE] &= ~ULL(0x1); 335 newVal = 0; 336 } else { 337 regs[APIC_INTERNAL_STATE] |= ULL(0x1); 338 return; 339 } 340 341 } 342 break; 343 case APIC_INTERRUPT_COMMAND_LOW: 344 panic("Local APIC Interrupt Command low" 345 " register unimplemented.\n"); 346 break; 347 case APIC_INTERRUPT_COMMAND_HIGH: 348 panic("Local APIC Interrupt Command high" 349 " register unimplemented.\n"); 350 break; 351 case APIC_LVT_TIMER: 352 case APIC_LVT_THERMAL_SENSOR: 353 case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS: 354 case APIC_LVT_LINT0: 355 case APIC_LVT_LINT1: 356 case APIC_LVT_ERROR: 357 { 358 uint64_t readOnlyMask = (1 << 12) | (1 << 14); 359 newVal = (val & ~readOnlyMask) | 360 (regs[reg] & readOnlyMask); 361 } 362 break; 363 case APIC_INITIAL_COUNT: 364 { 365 assert(clock); 366 newVal = bits(val, 31, 0); 367 uint32_t newCount = newVal * 368 (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]) * 16); 369 regs[APIC_CURRENT_COUNT] = newCount + curTick / clock; 370 // Find out how long a "tick" of the timer should take. 371 Tick timerTick = 16 * clock; 372 // Schedule on the edge of the next tick plus the new count. 373 Tick offset = curTick % timerTick; 374 if (offset) { 375 reschedule(apicTimerEvent, 376 curTick + (newCount + 1) * timerTick - offset, true); 377 } else { 378 reschedule(apicTimerEvent, 379 curTick + newCount * timerTick, true); 380 } 381 } 382 break; 383 case APIC_CURRENT_COUNT: 384 //Local APIC Current Count register is read only. 385 return; 386 case APIC_DIVIDE_CONFIGURATION: 387 newVal = val & 0xB; 388 break; 389 default: 390 break; 391 } 392 regs[reg] = newVal; 393 return; 394} 395 396X86ISA::Interrupts * 397X86LocalApicParams::create() 398{ 399 return new X86ISA::Interrupts(this); 400} 401