interrupts.cc (5647:b06b49498c79) interrupts.cc (5648:e8abda6e0980)
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 *

--- 41 unchanged lines hidden (view full) ---

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
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 *

--- 41 unchanged lines hidden (view full) ---

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"
58#include "arch/x86/interrupts.hh"
59#include "cpu/base.hh"
60
59#include "arch/x86/interrupts.hh"
60#include "cpu/base.hh"
61
61int divideFromConf(uint32_t conf)
62int
63divideFromConf(uint32_t conf)
62{
63 // This figures out what division we want from the division configuration
64 // register in the local APIC. The encoding is a little odd but it can
65 // be deciphered fairly easily.
66 int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
67 shift = (shift + 1) % 8;
68 return 1 << shift;
69}
70
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
71uint32_t
72X86ISA::Interrupts::readRegNoEffect(ApicRegIndex reg)
73namespace X86ISA
73{
74{
74 return regs[reg];
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;
75}
206}
207}
76
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
77uint32_t
236uint32_t
78X86ISA::Interrupts::readReg(ApicRegIndex reg, ThreadContext * tc)
237X86ISA::Interrupts::readReg(ApicRegIndex reg)
79{
80 if (reg >= APIC_TRIGGER_MODE(0) &&
81 reg <= APIC_TRIGGER_MODE(15)) {
82 panic("Local APIC Trigger Mode registers are unimplemented.\n");
83 }
84 switch (reg) {
85 case APIC_ARBITRATION_PRIORITY:
86 panic("Local APIC Arbitration Priority register unimplemented.\n");

--- 12 unchanged lines hidden (view full) ---

99 " register unimplemented.\n");
100 break;
101 case APIC_INTERRUPT_COMMAND_HIGH:
102 panic("Local APIC Interrupt Command high"
103 " register unimplemented.\n");
104 break;
105 case APIC_CURRENT_COUNT:
106 {
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");

--- 12 unchanged lines hidden (view full) ---

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 {
107 uint32_t val = regs[reg] - tc->getCpuPtr()->curCycle();
266 assert(clock);
267 uint32_t val = regs[reg] - curTick / clock;
108 val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
109 return val;
110 }
111 default:
112 break;
113 }
268 val /= (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
269 return val;
270 }
271 default:
272 break;
273 }
114 return readRegNoEffect(reg);
274 return regs[reg];
115}
116
117void
275}
276
277void
118X86ISA::Interrupts::setRegNoEffect(ApicRegIndex reg, uint32_t val)
278X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
119{
279{
120 regs[reg] = val;
121}
122
123void
124X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val, ThreadContext *tc)
125{
126 uint32_t newVal = val;
127 if (reg >= APIC_IN_SERVICE(0) &&
128 reg <= APIC_IN_SERVICE(15)) {
129 panic("Local APIC In-Service registers are unimplemented.\n");
130 }
131 if (reg >= APIC_TRIGGER_MODE(0) &&
132 reg <= APIC_TRIGGER_MODE(15)) {
133 panic("Local APIC Trigger Mode registers are unimplemented.\n");

--- 62 unchanged lines hidden (view full) ---

196 case APIC_LVT_ERROR:
197 {
198 uint64_t readOnlyMask = (1 << 12) | (1 << 14);
199 newVal = (val & ~readOnlyMask) |
200 (regs[reg] & readOnlyMask);
201 }
202 break;
203 case APIC_INITIAL_COUNT:
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");

--- 62 unchanged lines hidden (view full) ---

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:
204 newVal = bits(val, 31, 0);
205 regs[APIC_CURRENT_COUNT] =
206 tc->getCpuPtr()->curCycle() +
207 (16 * divideFromConf(regs[APIC_DIVIDE_CONFIGURATION])) * newVal;
208 //FIXME This should schedule the timer event.
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 }
209 break;
210 case APIC_CURRENT_COUNT:
211 //Local APIC Current Count register is read only.
212 return;
213 case APIC_DIVIDE_CONFIGURATION:
214 newVal = val & 0xB;
215 break;
216 default:
217 break;
218 }
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 }
219 setRegNoEffect(reg, newVal);
386 regs[reg] = newVal;
220 return;
221}
222
223X86ISA::Interrupts *
224X86LocalApicParams::create()
225{
226 return new X86ISA::Interrupts(this);
227}
387 return;
388}
389
390X86ISA::Interrupts *
391X86LocalApicParams::create()
392{
393 return new X86ISA::Interrupts(this);
394}