1 /////////////////////////////////////////////////////////////////////////
2 // $Id: apic.cc 14321 2021-07-25 18:02:36Z sshwarts $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2002-2019 Zwane Mwaikambo, Stanislav Shwartsman
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 /////////////////////////////////////////////////////////////////////////
22
23 #define NEED_CPU_REG_SHORTCUTS 1
24 #include "bochs.h"
25 #include "cpu.h"
26 #include "scalar_arith.h"
27 #include "iodev/iodev.h"
28
29 #if BX_SUPPORT_APIC
30
31 extern bool simulate_xapic;
32
33 #define LOG_THIS this->
34
35 #define BX_CPU_APIC(i) (&(BX_CPU(i)->lapic))
36
37 const unsigned BX_LAPIC_FIRST_VECTOR = 0x10;
38 const unsigned BX_LAPIC_LAST_VECTOR = 0xff;
39
40 ///////////// APIC BUS /////////////
41
apic_bus_deliver_interrupt(Bit8u vector,apic_dest_t dest,Bit8u delivery_mode,bool logical_dest,bool level,bool trig_mode)42 int apic_bus_deliver_interrupt(Bit8u vector, apic_dest_t dest, Bit8u delivery_mode, bool logical_dest, bool level, bool trig_mode)
43 {
44 if(delivery_mode == APIC_DM_LOWPRI)
45 {
46 if(! logical_dest) {
47 // I/O subsytem initiated interrupt with lowest priority delivery
48 // which is not supported in physical destination mode
49 return 0;
50 }
51 else {
52 return apic_bus_deliver_lowest_priority(vector, dest, trig_mode, 0);
53 }
54 }
55
56 // determine destination local apics and deliver
57 if(! logical_dest) {
58 // physical destination mode
59 if((dest & apic_id_mask) == apic_id_mask) {
60 return apic_bus_broadcast_interrupt(vector, delivery_mode, trig_mode, apic_id_mask);
61 }
62 else {
63 // the destination is single agent
64 for (unsigned i=0;i<BX_NUM_LOCAL_APICS;i++)
65 {
66 if(BX_CPU_APIC(i)->get_id() == dest) {
67 BX_CPU_APIC(i)->deliver(vector, delivery_mode, trig_mode);
68 return 1;
69 }
70 }
71
72 return 0;
73 }
74 }
75 else {
76 // logical destination mode
77 if(dest == 0) return 0;
78
79 bool interrupt_delivered = false;
80
81 for (int i=0; i<BX_NUM_LOCAL_APICS; i++) {
82 if(BX_CPU_APIC(i)->match_logical_addr(dest)) {
83 BX_CPU_APIC(i)->deliver(vector, delivery_mode, trig_mode);
84 interrupt_delivered = true;
85 }
86 }
87
88 return (int) interrupt_delivered;
89 }
90 }
91
apic_bus_deliver_lowest_priority(Bit8u vector,apic_dest_t dest,bool trig_mode,bool broadcast)92 int apic_bus_deliver_lowest_priority(Bit8u vector, apic_dest_t dest, bool trig_mode, bool broadcast)
93 {
94 int i;
95
96 if (! BX_CPU_APIC(0)->is_xapic()) {
97 // search for if focus processor exists
98 for (i=0; i<BX_NUM_LOCAL_APICS; i++) {
99 if(BX_CPU_APIC(i)->is_focus(vector)) {
100 BX_CPU_APIC(i)->deliver(vector, APIC_DM_LOWPRI, trig_mode);
101 return 1;
102 }
103 }
104 }
105
106 // focus processor not found, looking for lowest priority agent
107 int lowest_priority_agent = -1, lowest_priority = 0x100, priority;
108
109 for (i=0; i<BX_NUM_LOCAL_APICS; i++) {
110 if(broadcast || BX_CPU_APIC(i)->match_logical_addr(dest)) {
111 if (BX_CPU_APIC(i)->is_xapic())
112 priority = BX_CPU_APIC(i)->get_tpr();
113 else
114 priority = BX_CPU_APIC(i)->get_apr();
115 if(priority < lowest_priority) {
116 lowest_priority = priority;
117 lowest_priority_agent = i;
118 }
119 }
120 }
121
122 if(lowest_priority_agent >= 0)
123 {
124 BX_CPU_APIC(lowest_priority_agent)->deliver(vector, APIC_DM_LOWPRI, trig_mode);
125 return 1;
126 }
127
128 return 0;
129 }
130
apic_bus_broadcast_interrupt(Bit8u vector,Bit8u delivery_mode,bool trig_mode,int exclude_cpu)131 int apic_bus_broadcast_interrupt(Bit8u vector, Bit8u delivery_mode, bool trig_mode, int exclude_cpu)
132 {
133 if(delivery_mode == APIC_DM_LOWPRI)
134 {
135 return apic_bus_deliver_lowest_priority(vector, 0 /* doesn't matter */, trig_mode, 1);
136 }
137
138 // deliver to all bus agents except 'exclude_cpu'
139 for (int i=0; i<BX_NUM_LOCAL_APICS; i++) {
140 if(i == exclude_cpu) continue;
141 BX_CPU_APIC(i)->deliver(vector, delivery_mode, trig_mode);
142 }
143
144 return 1;
145 }
146
apic_bus_broadcast_eoi(Bit8u vector)147 static void apic_bus_broadcast_eoi(Bit8u vector)
148 {
149 DEV_ioapic_receive_eoi(vector);
150 }
151
152 #endif
153
154 // available even if APIC is not compiled in
apic_bus_deliver_smi(void)155 BOCHSAPI_MSVCONLY void apic_bus_deliver_smi(void)
156 {
157 BX_CPU(0)->deliver_SMI();
158 }
159
apic_bus_broadcast_smi(void)160 void apic_bus_broadcast_smi(void)
161 {
162 for (unsigned i=0; i<BX_SMP_PROCESSORS; i++)
163 BX_CPU(i)->deliver_SMI();
164 }
165
166 #if BX_SUPPORT_APIC
167
168 ////////////////////////////////////
169
bx_local_apic_c(BX_CPU_C * mycpu,unsigned id)170 bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu, unsigned id)
171 : base_addr(BX_LAPIC_BASE_ADDR), cpu(mycpu)
172 {
173 apic_id = id;
174 #if BX_SUPPORT_SMP
175 if (apic_id >= bx_cpu_count)
176 BX_PANIC(("PANIC: invalid APIC_ID assigned %d (max = %d)", apic_id, bx_cpu_count));
177 #else
178 if (apic_id != 0)
179 BX_PANIC(("PANIC: invalid APIC_ID assigned %d", apic_id));
180 #endif
181
182 char name[16], logname[16];
183 sprintf(name, "APIC%x", apic_id);
184 sprintf(logname, "apic%x", apic_id);
185 put(logname, name);
186
187 // Register a non-active timer for use when the timer is started.
188 timer_handle = bx_pc_system.register_timer_ticks(this,
189 bx_local_apic_c::periodic_smf, 0, 0, 0, "lapic");
190 timer_active = 0;
191
192 #if BX_SUPPORT_VMX >= 2
193 // Register a non-active timer for VMX preemption timer.
194 vmx_timer_handle = bx_pc_system.register_timer_ticks(this,
195 bx_local_apic_c::vmx_preemption_timer_expired, 0, 0, 0, "vmx_preemption");
196 BX_DEBUG(("vmx_timer is = %d", vmx_timer_handle));
197 vmx_preemption_timer_rate = VMX_MISC_PREEMPTION_TIMER_RATE;
198 vmx_timer_active = 0;
199 #endif
200
201 #if BX_SUPPORT_MONITOR_MWAIT
202 mwaitx_timer_handle = bx_pc_system.register_timer_ticks(this,
203 bx_local_apic_c::mwaitx_timer_expired, 0, 0, 0, "mwaitx_timer");
204 BX_DEBUG(("mwaitx_timer is = %d", mwaitx_timer_handle));
205 mwaitx_timer_active = 0;
206 #endif
207
208 xapic = simulate_xapic; // xAPIC or legacy APIC
209
210 reset(BX_RESET_HARDWARE);
211 }
212
reset(unsigned type)213 void bx_local_apic_c::reset(unsigned type)
214 {
215 int i;
216
217 // default address for a local APIC, can be moved
218 base_addr = BX_LAPIC_BASE_ADDR;
219 error_status = shadow_error_status = 0;
220 ldr = 0;
221 dest_format = 0xf;
222 icr_hi = 0;
223 icr_lo = 0;
224 task_priority = 0;
225
226 for(i=0; i<8; i++) {
227 irr[i] = isr[i] = tmr[i] = 0;
228 #if BX_CPU_LEVEL >= 6
229 ier[i] = 0xFFFFFFFF; // all interrupts are enabled
230 #endif
231 }
232
233 timer_divconf = 0;
234 timer_divide_factor = 1;
235 timer_initial = 0;
236 timer_current = 0;
237 ticksInitial = 0;
238
239 if(timer_active) {
240 bx_pc_system.deactivate_timer(timer_handle);
241 timer_active = 0;
242 }
243
244 #if BX_SUPPORT_VMX >= 2
245 if(vmx_timer_active) {
246 bx_pc_system.deactivate_timer(vmx_timer_handle);
247 vmx_timer_active = 0;
248 }
249 #endif
250
251 #if BX_SUPPORT_MONITOR_MWAIT
252 if(mwaitx_timer_active) {
253 bx_pc_system.deactivate_timer(mwaitx_timer_handle);
254 mwaitx_timer_active = 0;
255 }
256 #endif
257
258 for(i=0; i<APIC_LVT_ENTRIES; i++) {
259 lvt[i] = 0x10000; // all LVT are masked
260 }
261
262 // split spurious vector register to 3 fields
263 spurious_vector = 0xff;
264 software_enabled = 0;
265 focus_disable = 0;
266
267 mode = BX_APIC_XAPIC_MODE;
268
269 if (xapic)
270 apic_version_id = 0x00050014; // P4 has 6 LVT entries
271 else
272 apic_version_id = 0x00030010; // P6 has 4 LVT entries
273
274 #if BX_CPU_LEVEL >= 6
275 xapic_ext = 0;
276 #endif
277 }
278
279 #if BX_CPU_LEVEL >= 6
enable_xapic_extensions(void)280 void bx_local_apic_c::enable_xapic_extensions(void)
281 {
282 apic_version_id |= 0x80000000;
283 xapic_ext = BX_XAPIC_EXT_SUPPORT_IER | BX_XAPIC_EXT_SUPPORT_SEOI;
284 }
285 #endif
286
set_base(bx_phy_address newbase)287 void bx_local_apic_c::set_base(bx_phy_address newbase)
288 {
289 #if BX_CPU_LEVEL >= 6
290 if (mode == BX_APIC_X2APIC_MODE)
291 ldr = ((apic_id & 0xfffffff0) << 16) | (1 << (apic_id & 0xf));
292 #endif
293 mode = (newbase >> 10) & 3;
294 newbase &= ~((bx_phy_address) 0xfff);
295 base_addr = newbase;
296 BX_INFO(("allocate APIC id=%d (MMIO %s) to 0x" FMT_PHY_ADDRX,
297 apic_id, (mode == BX_APIC_XAPIC_MODE) ? "enabled" : "disabled", newbase));
298
299 if (mode == BX_APIC_GLOBALLY_DISABLED) {
300 // if local apic becomes globally disabled reset some fields back to defaults
301 write_spurious_interrupt_register(0xff);
302 }
303 }
304
is_selected(bx_phy_address addr)305 bool bx_local_apic_c::is_selected(bx_phy_address addr)
306 {
307 if (mode != BX_APIC_XAPIC_MODE) return 0;
308
309 if((addr & ~0xfff) == base_addr) {
310 if((addr & 0xf) != 0)
311 BX_INFO(("warning: misaligned APIC access. addr=0x" FMT_PHY_ADDRX, addr));
312 return 1;
313 }
314 return 0;
315 }
316
read(bx_phy_address addr,void * data,unsigned len)317 void bx_local_apic_c::read(bx_phy_address addr, void *data, unsigned len)
318 {
319 if((addr & ~0x3) != ((addr+len-1) & ~0x3)) {
320 BX_PANIC(("APIC read at address 0x" FMT_PHY_ADDRX " spans 32-bit boundary !", addr));
321 return;
322 }
323 Bit32u value = read_aligned(addr & ~0x3);
324 if(len == 4) { // must be 32-bit aligned
325 *((Bit32u *)data) = value;
326 return;
327 }
328 // handle partial read, independent of endian-ness
329 value >>= (addr&3)*8;
330 if (len == 1)
331 *((Bit8u *) data) = value & 0xff;
332 else if (len == 2)
333 *((Bit16u *)data) = value & 0xffff;
334 else
335 BX_PANIC(("Unsupported APIC read at address 0x" FMT_PHY_ADDRX ", len=%d", addr, len));
336 }
337
write(bx_phy_address addr,void * data,unsigned len)338 void bx_local_apic_c::write(bx_phy_address addr, void *data, unsigned len)
339 {
340 if (len != 4) {
341 BX_PANIC(("APIC write with len=%d (should be 4)", len));
342 return;
343 }
344
345 if(addr & 0xf) {
346 BX_PANIC(("APIC write at unaligned address 0x" FMT_PHY_ADDRX, addr));
347 return;
348 }
349
350 write_aligned(addr, *((Bit32u*) data));
351 }
352
353 // APIC read: 4 byte read from 16-byte aligned APIC address
read_aligned(bx_phy_address addr)354 Bit32u bx_local_apic_c::read_aligned(bx_phy_address addr)
355 {
356 BX_ASSERT((addr & 0xf) == 0);
357 Bit32u data = 0; // default value for unimplemented registers
358
359 unsigned apic_reg = addr & 0xff0;
360 BX_DEBUG(("LAPIC read from register 0x%04x", apic_reg));
361
362 #if BX_CPU_LEVEL >= 6
363 if (apic_reg >= 0x400 && !cpu->is_cpu_extension_supported(BX_ISA_XAPIC_EXT))
364 apic_reg = 0xffffffff; // choose some obviosly invalid register if extended xapic is not supported
365 #endif
366
367 switch(apic_reg) {
368 case BX_LAPIC_ID: // local APIC id
369 data = apic_id << 24; break;
370 case BX_LAPIC_VERSION: // local APIC version
371 data = apic_version_id; break;
372 case BX_LAPIC_TPR: // task priority
373 data = task_priority & 0xff; break;
374 case BX_LAPIC_ARBITRATION_PRIORITY:
375 data = get_apr(); break;
376 case BX_LAPIC_PPR: // processor priority
377 data = get_ppr(); break;
378 case BX_LAPIC_EOI: // EOI
379 /*
380 * Read-modify-write operations should operate without generating
381 * exceptions, and are used by some operating systems to EOI.
382 * The results of reads should be ignored by the OS.
383 */
384 break;
385 case BX_LAPIC_LDR: // logical destination
386 data = (ldr & apic_id_mask) << 24;
387 break;
388 case BX_LAPIC_DESTINATION_FORMAT:
389 data = ((dest_format & 0xf) << 28) | 0x0fffffff;
390 break;
391 case BX_LAPIC_SPURIOUS_VECTOR:
392 {
393 Bit32u reg = spurious_vector;
394 if(software_enabled) reg |= 0x100;
395 if(focus_disable) reg |= 0x200;
396 data = reg;
397 }
398 break;
399 case BX_LAPIC_ISR1: case BX_LAPIC_ISR2:
400 case BX_LAPIC_ISR3: case BX_LAPIC_ISR4:
401 case BX_LAPIC_ISR5: case BX_LAPIC_ISR6:
402 case BX_LAPIC_ISR7: case BX_LAPIC_ISR8:
403 {
404 int index = (apic_reg - BX_LAPIC_ISR1) >> 4;
405 data = isr[index];
406 break;
407 }
408 case BX_LAPIC_TMR1: case BX_LAPIC_TMR2:
409 case BX_LAPIC_TMR3: case BX_LAPIC_TMR4:
410 case BX_LAPIC_TMR5: case BX_LAPIC_TMR6:
411 case BX_LAPIC_TMR7: case BX_LAPIC_TMR8:
412 {
413 int index = (apic_reg - BX_LAPIC_TMR1) >> 4;
414 data = tmr[index];
415 break;
416 }
417 case BX_LAPIC_IRR1: case BX_LAPIC_IRR2:
418 case BX_LAPIC_IRR3: case BX_LAPIC_IRR4:
419 case BX_LAPIC_IRR5: case BX_LAPIC_IRR6:
420 case BX_LAPIC_IRR7: case BX_LAPIC_IRR8:
421 {
422 int index = (apic_reg - BX_LAPIC_IRR1) >> 4;
423 data = irr[index];
424 break;
425 }
426 case BX_LAPIC_ESR: // error status reg
427 data = error_status; break;
428 case BX_LAPIC_ICR_LO: // interrupt command reg 0-31
429 data = icr_lo; break;
430 case BX_LAPIC_ICR_HI: // interrupt command reg 31-63
431 data = icr_hi; break;
432 case BX_LAPIC_LVT_TIMER: // LVT Timer Reg
433 case BX_LAPIC_LVT_THERMAL: // LVT Thermal Monitor
434 case BX_LAPIC_LVT_PERFMON: // LVT Performance Counter
435 case BX_LAPIC_LVT_LINT0: // LVT LINT0 Reg
436 case BX_LAPIC_LVT_LINT1: // LVT Lint1 Reg
437 case BX_LAPIC_LVT_ERROR: // LVT Error Reg
438 {
439 int index = (apic_reg - BX_LAPIC_LVT_TIMER) >> 4;
440 data = lvt[index];
441 break;
442 }
443 case BX_LAPIC_LVT_CMCI:
444 data = lvt[APIC_LVT_CMCI];
445 break;
446 case BX_LAPIC_TIMER_INITIAL_COUNT: // initial count for timer
447 data = timer_initial;
448 break;
449 case BX_LAPIC_TIMER_CURRENT_COUNT: // current count for timer
450 data = get_current_timer_count();
451 break;
452 case BX_LAPIC_TIMER_DIVIDE_CFG: // timer divide configuration
453 data = timer_divconf;
454 break;
455 #if BX_CPU_LEVEL >= 6
456 case BX_LAPIC_EXT_APIC_FEATURE:
457 /* report extended xAPIC capabilities */
458 data = BX_XAPIC_EXT_SUPPORT_IER | BX_XAPIC_EXT_SUPPORT_SEOI;
459 break;
460 case BX_LAPIC_EXT_APIC_CONTROL:
461 /* report enabled extended xAPIC capabilities */
462 data = xapic_ext;
463 break;
464 case BX_LAPIC_SPECIFIC_EOI:
465 /*
466 * Read-modify-write operations should operate without generating
467 * exceptions, and are used by some operating systems to EOI.
468 * The results of reads should be ignored by the OS.
469 */
470 break;
471 case BX_LAPIC_IER1: case BX_LAPIC_IER2:
472 case BX_LAPIC_IER3: case BX_LAPIC_IER4:
473 case BX_LAPIC_IER5: case BX_LAPIC_IER6:
474 case BX_LAPIC_IER7: case BX_LAPIC_IER8:
475 {
476 int index = (apic_reg - BX_LAPIC_IER1) >> 4;
477 data = ier[index];
478 break;
479 }
480 #endif
481 default:
482 shadow_error_status |= APIC_ERR_ILLEGAL_ADDR;
483 // but for now I want to know about it in case I missed some.
484 BX_ERROR(("APIC read: register %x not implemented", apic_reg));
485 }
486
487 BX_DEBUG(("read from APIC address 0x" FMT_PHY_ADDRX " = %08x", addr, data));
488 return data;
489 }
490
491 // APIC write: 4 byte write to 16-byte aligned APIC address
write_aligned(bx_phy_address addr,Bit32u value)492 void bx_local_apic_c::write_aligned(bx_phy_address addr, Bit32u value)
493 {
494 BX_ASSERT((addr & 0xf) == 0);
495
496 unsigned apic_reg = addr & 0xff0;
497 BX_DEBUG(("LAPIC write 0x%08x to register 0x%04x", value, apic_reg));
498
499 #if BX_CPU_LEVEL >= 6
500 if (apic_reg >= 0x400 && !cpu->is_cpu_extension_supported(BX_ISA_XAPIC_EXT))
501 apic_reg = 0xffffffff; // choose some obviosly invalid register if extended xapic is not supported
502 #endif
503
504 switch(apic_reg) {
505 case BX_LAPIC_TPR: // task priority
506 set_tpr(value & 0xff);
507 break;
508 case BX_LAPIC_EOI: // EOI
509 receive_EOI(value);
510 break;
511 case BX_LAPIC_LDR: // logical destination
512 ldr = (value >> 24) & apic_id_mask;
513 BX_DEBUG(("set logical destination to %08x", ldr));
514 break;
515 case BX_LAPIC_DESTINATION_FORMAT:
516 dest_format = (value >> 28) & 0xf;
517 BX_DEBUG(("set destination format to %02x", dest_format));
518 break;
519 case BX_LAPIC_SPURIOUS_VECTOR:
520 write_spurious_interrupt_register(value);
521 break;
522 case BX_LAPIC_ESR: // error status reg
523 // Here's what the IA-devguide-3 says on p.7-45:
524 // The ESR is a read/write register and is reset after being written to
525 // by the processor. A write to the ESR must be done just prior to
526 // reading the ESR to allow the register to be updated.
527 error_status = shadow_error_status;
528 shadow_error_status = 0;
529 break;
530 case BX_LAPIC_ICR_LO: // interrupt command reg 0-31
531 icr_lo = value & ~(1<<12); // force delivery status bit = 0(idle)
532 send_ipi((icr_hi >> 24) & 0xff, icr_lo);
533 break;
534 case BX_LAPIC_ICR_HI: // interrupt command reg 31-63
535 icr_hi = value & 0xff000000;
536 break;
537 case BX_LAPIC_LVT_TIMER: // LVT Timer Reg
538 case BX_LAPIC_LVT_THERMAL: // LVT Thermal Monitor
539 case BX_LAPIC_LVT_PERFMON: // LVT Performance Counter
540 case BX_LAPIC_LVT_LINT0: // LVT LINT0 Reg
541 case BX_LAPIC_LVT_LINT1: // LVT LINT1 Reg
542 case BX_LAPIC_LVT_ERROR: // LVT Error Reg
543 case BX_LAPIC_LVT_CMCI:
544 set_lvt_entry(apic_reg, value);
545 break;
546 case BX_LAPIC_TIMER_INITIAL_COUNT:
547 set_initial_timer_count(value);
548 break;
549 case BX_LAPIC_TIMER_DIVIDE_CFG:
550 // only bits 3, 1, and 0 are writable
551 timer_divconf = value & 0xb;
552 set_divide_configuration(timer_divconf);
553 break;
554 /* all read-only registers go here */
555 case BX_LAPIC_ID: // local APIC id
556 case BX_LAPIC_VERSION: // local APIC version
557 case BX_LAPIC_ARBITRATION_PRIORITY:
558 case BX_LAPIC_RRD:
559 case BX_LAPIC_PPR: // processor priority
560 // ISRs not writable
561 case BX_LAPIC_ISR1: case BX_LAPIC_ISR2:
562 case BX_LAPIC_ISR3: case BX_LAPIC_ISR4:
563 case BX_LAPIC_ISR5: case BX_LAPIC_ISR6:
564 case BX_LAPIC_ISR7: case BX_LAPIC_ISR8:
565 // TMRs not writable
566 case BX_LAPIC_TMR1: case BX_LAPIC_TMR2:
567 case BX_LAPIC_TMR3: case BX_LAPIC_TMR4:
568 case BX_LAPIC_TMR5: case BX_LAPIC_TMR6:
569 case BX_LAPIC_TMR7: case BX_LAPIC_TMR8:
570 // IRRs not writable
571 case BX_LAPIC_IRR1: case BX_LAPIC_IRR2:
572 case BX_LAPIC_IRR3: case BX_LAPIC_IRR4:
573 case BX_LAPIC_IRR5: case BX_LAPIC_IRR6:
574 case BX_LAPIC_IRR7: case BX_LAPIC_IRR8:
575 // current count for timer
576 case BX_LAPIC_TIMER_CURRENT_COUNT:
577 // all read-only registers should fall into this line
578 BX_INFO(("warning: write to read-only APIC register 0x%x", apic_reg));
579 break;
580 #if BX_CPU_LEVEL >= 6
581 case BX_LAPIC_EXT_APIC_FEATURE:
582 // all read-only registers should fall into this line
583 BX_INFO(("warning: write to read-only APIC register 0x%x", apic_reg));
584 break;
585 case BX_LAPIC_EXT_APIC_CONTROL:
586 /* set extended xAPIC capabilities */
587 xapic_ext = value & (BX_XAPIC_EXT_SUPPORT_IER | BX_XAPIC_EXT_SUPPORT_SEOI);
588 break;
589 case BX_LAPIC_SPECIFIC_EOI:
590 receive_SEOI(value & 0xff);
591 break;
592 case BX_LAPIC_IER1: case BX_LAPIC_IER2:
593 case BX_LAPIC_IER3: case BX_LAPIC_IER4:
594 case BX_LAPIC_IER5: case BX_LAPIC_IER6:
595 case BX_LAPIC_IER7: case BX_LAPIC_IER8:
596 {
597 if ((xapic_ext & BX_XAPIC_EXT_SUPPORT_IER) == 0) {
598 BX_ERROR(("IER writes are currently disabled reg %x", apic_reg));
599 break;
600 }
601
602 int index = (apic_reg - BX_LAPIC_IER1) >> 4;
603 ier[index] = value;
604 }
605 break;
606 #endif
607 default:
608 shadow_error_status |= APIC_ERR_ILLEGAL_ADDR;
609 // but for now I want to know about it in case I missed some.
610 BX_ERROR(("APIC write: register %x not implemented", apic_reg));
611 }
612 }
613
set_lvt_entry(unsigned apic_reg,Bit32u value)614 void bx_local_apic_c::set_lvt_entry(unsigned apic_reg, Bit32u value)
615 {
616 static Bit32u lvt_mask[] = {
617 0x000710ff, /* TIMER */
618 0x000117ff, /* THERMAL */
619 0x000117ff, /* PERFMON */
620 0x0001f7ff, /* LINT0 */
621 0x0001f7ff, /* LINT1 */
622 0x000110ff, /* ERROR */
623 0x000117ff, /* CMCI */
624 };
625
626 unsigned lvt_entry = (apic_reg == BX_LAPIC_LVT_CMCI) ? APIC_LVT_CMCI : (apic_reg - BX_LAPIC_LVT_TIMER) >> 4;
627 #if BX_CPU_LEVEL >= 6
628 if (apic_reg == BX_LAPIC_LVT_TIMER) {
629 if (! cpu->is_cpu_extension_supported(BX_ISA_TSC_DEADLINE)) {
630 value &= ~0x40000; // cannot enable TSC-Deadline when not supported
631 }
632 else {
633 if ((value ^ lvt[lvt_entry]) & 0x40000) {
634 // Transition between TSC-Deadline and other timer modes disarm the timer
635 if(timer_active) {
636 bx_pc_system.deactivate_timer(timer_handle);
637 timer_active = 0;
638 }
639 }
640 }
641 }
642 #endif
643
644 lvt[lvt_entry] = value & lvt_mask[lvt_entry];
645 if(! software_enabled) {
646 lvt[lvt_entry] |= 0x10000;
647 }
648 }
649
send_ipi(apic_dest_t dest,Bit32u lo_cmd)650 void bx_local_apic_c::send_ipi(apic_dest_t dest, Bit32u lo_cmd)
651 {
652 int dest_shorthand = (lo_cmd >> 18) & 3;
653 int trig_mode = (lo_cmd >> 15) & 1;
654 int level = (lo_cmd >> 14) & 1;
655 int logical_dest = (lo_cmd >> 11) & 1;
656 int delivery_mode = (lo_cmd >> 8) & 7;
657 int vector = (lo_cmd & 0xff);
658 int accepted = 0;
659
660 if(delivery_mode == APIC_DM_INIT)
661 {
662 if(level == 0 && trig_mode == 1) {
663 // special mode in local apic. See "INIT Level Deassert" in the
664 // Intel Soft. Devel. Guide Vol 3, page 7-34. This magic code
665 // causes all APICs(regardless of dest address) to set their
666 // arbitration ID to their APIC ID. Not supported by Pentium 4
667 // and Intel Xeon processors.
668 return; // we not model APIC bus arbitration ID anyway
669 }
670 }
671
672 switch(dest_shorthand) {
673 case 0: // no shorthand, use real destination value
674 accepted = apic_bus_deliver_interrupt(vector, dest, delivery_mode, logical_dest, level, trig_mode);
675 break;
676 case 1: // self
677 trigger_irq(vector, trig_mode);
678 accepted = 1;
679 break;
680 case 2: // all including self
681 accepted = apic_bus_broadcast_interrupt(vector, delivery_mode, trig_mode, apic_id_mask);
682 break;
683 case 3: // all but self
684 accepted = apic_bus_broadcast_interrupt(vector, delivery_mode, trig_mode, get_id());
685 break;
686 default:
687 BX_PANIC(("Invalid desination shorthand %#x", dest_shorthand));
688 }
689
690 if(! accepted) {
691 BX_DEBUG(("An IPI wasn't accepted, raise APIC_ERR_TX_ACCEPT_ERR"));
692 shadow_error_status |= APIC_ERR_TX_ACCEPT_ERR;
693 }
694 }
695
write_spurious_interrupt_register(Bit32u value)696 void bx_local_apic_c::write_spurious_interrupt_register(Bit32u value)
697 {
698 BX_DEBUG(("write of %08x to spurious interrupt register", value));
699
700 if (xapic)
701 spurious_vector = value & 0xff;
702 else
703 // bits 0-3 of the spurious vector hardwired to '1
704 spurious_vector = (value & 0xf0) | 0xf;
705
706 software_enabled = (value >> 8) & 1;
707 focus_disable = (value >> 9) & 1;
708
709 if(! software_enabled) {
710 for(unsigned i=0; i<APIC_LVT_ENTRIES; i++) {
711 lvt[i] |= 0x10000; // all LVT are masked
712 }
713 }
714 }
715
receive_EOI(Bit32u value)716 void bx_local_apic_c::receive_EOI(Bit32u value)
717 {
718 BX_DEBUG(("Wrote 0x%x to EOI", value));
719 int vec = highest_priority_int(isr);
720 if (vec < 0) {
721 BX_DEBUG(("EOI written without any bit in ISR"));
722 }
723 else {
724 if ((Bit32u) vec != spurious_vector) {
725 BX_DEBUG(("local apic received EOI, hopefully for vector 0x%02x", vec));
726 clear_vector(isr, vec);
727 if(get_vector(tmr, vec)) {
728 apic_bus_broadcast_eoi(vec);
729 clear_vector(tmr, vec);
730 }
731 service_local_apic();
732 }
733 }
734
735 if(bx_dbg.apic) print_status();
736 }
737
738 #if BX_CPU_LEVEL >= 6
receive_SEOI(Bit8u vec)739 void bx_local_apic_c::receive_SEOI(Bit8u vec)
740 {
741 if ((xapic_ext & BX_XAPIC_EXT_SUPPORT_SEOI) == 0) {
742 BX_ERROR(("SEOI functionality is disabled"));
743 return;
744 }
745
746 if (get_vector(isr, vec)) {
747 BX_DEBUG(("local apic received SEOI for vector 0x%02x", vec));
748 clear_vector(isr, vec);
749 if(get_vector(tmr, vec)) {
750 apic_bus_broadcast_eoi(vec);
751 clear_vector(tmr, vec);
752 }
753 service_local_apic();
754 }
755
756 if(bx_dbg.apic) print_status();
757 }
758 #endif
759
startup_msg(Bit8u vector)760 void bx_local_apic_c::startup_msg(Bit8u vector)
761 {
762 cpu->deliver_SIPI(vector);
763 }
764
get_vector(Bit32u * reg,unsigned vector)765 bool bx_local_apic_c::get_vector(Bit32u *reg, unsigned vector)
766 {
767 return (reg[vector / 32] >> (vector % 32)) & 0x1;
768 }
769
set_vector(Bit32u * reg,unsigned vector)770 void bx_local_apic_c::set_vector(Bit32u *reg, unsigned vector)
771 {
772 reg[vector / 32] |= (1 << (vector % 32));
773 }
774
clear_vector(Bit32u * reg,unsigned vector)775 void bx_local_apic_c::clear_vector(Bit32u *reg, unsigned vector)
776 {
777 reg[vector / 32] &= ~(1 << (vector % 32));
778 }
779
highest_priority_int(Bit32u * array)780 int bx_local_apic_c::highest_priority_int(Bit32u *array)
781 {
782 for (int reg=7; reg>=0; reg--) {
783 Bit32u tmp = array[reg];
784 #if BX_CPU_LEVEL >= 6
785 tmp &= ier[reg];
786 #endif
787 // ignore of interrupt vectors < 16 happen naturally as there is no way to ISR to it
788 // if (reg == 0) tmp &= 0xffff0000;
789 if (tmp) {
790 int vector = (reg * 32) + (31 - lzcntd(tmp));
791 return vector;
792 }
793 }
794
795 return -1;
796 }
797
service_local_apic(void)798 void bx_local_apic_c::service_local_apic(void)
799 {
800 if(bx_dbg.apic) {
801 BX_INFO(("service_local_apic()"));
802 print_status();
803 }
804
805 if(cpu->is_pending(BX_EVENT_PENDING_LAPIC_INTR)) return; // INTR already up; do nothing
806
807 // find first interrupt in irr.
808 int first_irr = highest_priority_int(irr);
809 if (first_irr < 0) return; // no interrupts, leave INTR=0
810 int first_isr = highest_priority_int(isr);
811 if (first_isr >= 0 && first_irr <= first_isr) {
812 BX_DEBUG(("lapic(%d): not delivering int 0x%02x because int 0x%02x is in service", apic_id, first_irr, first_isr));
813 return;
814 }
815 if(((Bit32u)(first_irr) & 0xf0) <= (task_priority & 0xf0)) {
816 BX_DEBUG(("lapic(%d): not delivering int 0x%02X because task_priority is 0x%02X", apic_id, first_irr, task_priority));
817 return;
818 }
819 // interrupt has appeared in irr. Raise INTR. When the CPU
820 // acknowledges, we will run highest_priority_int again and
821 // return it.
822 BX_DEBUG(("service_local_apic(): setting INTR=1 for vector 0x%02x", first_irr));
823 cpu->signal_event(BX_EVENT_PENDING_LAPIC_INTR);
824 }
825
deliver(Bit8u vector,Bit8u delivery_mode,Bit8u trig_mode)826 bool bx_local_apic_c::deliver(Bit8u vector, Bit8u delivery_mode, Bit8u trig_mode)
827 {
828 switch(delivery_mode) {
829 case APIC_DM_FIXED:
830 case APIC_DM_LOWPRI:
831 BX_DEBUG(("Deliver lowest priority of fixed interrupt vector %02x", vector));
832 trigger_irq(vector, trig_mode);
833 break;
834 case APIC_DM_SMI:
835 BX_INFO(("Deliver SMI"));
836 cpu->deliver_SMI();
837 return 1;
838 case APIC_DM_NMI:
839 BX_INFO(("Deliver NMI"));
840 cpu->deliver_NMI();
841 return 1;
842 case APIC_DM_INIT:
843 BX_INFO(("Deliver INIT IPI"));
844 cpu->deliver_INIT();
845 break;
846 case APIC_DM_SIPI:
847 BX_INFO(("Deliver Start Up IPI"));
848 startup_msg(vector);
849 break;
850 case APIC_DM_EXTINT:
851 BX_DEBUG(("Deliver EXTINT vector %02x", vector));
852 trigger_irq(vector, trig_mode, 1);
853 break;
854 default:
855 return 0;
856 }
857
858 return 1;
859 }
860
trigger_irq(Bit8u vector,unsigned trigger_mode,bool bypass_irr_isr)861 void bx_local_apic_c::trigger_irq(Bit8u vector, unsigned trigger_mode, bool bypass_irr_isr)
862 {
863 BX_DEBUG(("trigger interrupt vector=0x%02x", vector));
864
865 if(/* vector > BX_LAPIC_LAST_VECTOR || */ vector < BX_LAPIC_FIRST_VECTOR) {
866 shadow_error_status |= APIC_ERR_RX_ILLEGAL_VEC;
867 BX_INFO(("bogus vector %#x, ignoring ...", vector));
868 return;
869 }
870
871 BX_DEBUG(("triggered vector %#02x", vector));
872
873 if(! bypass_irr_isr) {
874 if(get_vector(irr, vector)) {
875 BX_DEBUG(("triggered vector %#02x not accepted", vector));
876 return;
877 }
878 }
879
880 set_vector(irr, vector);
881 if (trigger_mode)
882 set_vector(tmr, vector); // set for level triggered
883 else
884 clear_vector(tmr, vector);
885
886 service_local_apic();
887 }
888
untrigger_irq(Bit8u vector,unsigned trigger_mode)889 void bx_local_apic_c::untrigger_irq(Bit8u vector, unsigned trigger_mode)
890 {
891 BX_DEBUG(("untrigger interrupt vector=0x%02x", vector));
892 // hardware says "no more". clear the bit. If the CPU hasn't yet
893 // acknowledged the interrupt, it will never be serviced.
894 BX_ASSERT(get_vector(irr, vector));
895 clear_vector(irr, vector);
896 if(bx_dbg.apic) print_status();
897 }
898
acknowledge_int(void)899 Bit8u bx_local_apic_c::acknowledge_int(void)
900 {
901 // CPU calls this when it is ready to service one interrupt
902 if(! cpu->is_pending(BX_EVENT_PENDING_LAPIC_INTR))
903 BX_PANIC(("APIC %d acknowledged an interrupt, but INTR=0", apic_id));
904
905 int vector = highest_priority_int(irr);
906 if (vector < 0 || (vector & 0xf0) <= get_ppr()) {
907 cpu->clear_event(BX_EVENT_PENDING_LAPIC_INTR);
908 return spurious_vector;
909 }
910
911 BX_ASSERT(get_vector(irr, vector));
912 BX_DEBUG(("acknowledge_int() returning vector 0x%02x", vector));
913 clear_vector(irr, vector);
914 set_vector(isr, vector);
915 if(bx_dbg.apic) {
916 BX_INFO(("Status after setting isr:"));
917 print_status();
918 }
919
920 cpu->clear_event(BX_EVENT_PENDING_LAPIC_INTR);
921 service_local_apic(); // will set INTR again if another is ready
922 return vector;
923 }
924
print_status(void)925 void bx_local_apic_c::print_status(void)
926 {
927 BX_INFO(("lapic %d: status is {:", apic_id));
928 for(unsigned vec=0; vec<=BX_LAPIC_LAST_VECTOR; vec++) {
929 if(get_vector(irr, vec) || get_vector(isr, vec)) {
930 BX_INFO(("vec: %u, irr=%d, isr=%d", vec, get_vector(irr, vec), get_vector(isr, vec)));
931 }
932 }
933 BX_INFO(("}"));
934 }
935
match_logical_addr(apic_dest_t address)936 bool bx_local_apic_c::match_logical_addr(apic_dest_t address)
937 {
938 bool match = false;
939
940 #if BX_CPU_LEVEL >= 6
941 if (mode == BX_APIC_X2APIC_MODE) {
942 // only cluster model supported in x2apic mode
943 if (address == 0xffffffff) // // broadcast all
944 return true;
945 if ((address & 0xffff0000) == (ldr & 0xffff0000))
946 match = ((address & ldr & 0x0000ffff) != 0);
947 return match;
948 }
949 #endif
950
951 if (dest_format == 0xf) {
952 // flat model
953 match = ((address & ldr) != 0);
954 BX_DEBUG(("comparing MDA %02x to my LDR %02x -> %s", address,
955 ldr, match ? "Match" : "Not a match"));
956 }
957 else if (dest_format == 0) {
958 // cluster model
959 if (address == 0xff) // broadcast all
960 return true;
961
962 if ((unsigned)(address & 0xf0) == (unsigned)(ldr & 0xf0))
963 match = ((address & ldr & 0x0f) != 0);
964 }
965 else {
966 BX_PANIC(("bx_local_apic_c::match_logical_addr: unsupported dest format 0x%x", dest_format));
967 }
968
969 return match;
970 }
971
get_ppr(void)972 Bit8u bx_local_apic_c::get_ppr(void)
973 {
974 int ppr = highest_priority_int(isr);
975
976 if((ppr < 0) || ((task_priority & 0xF0) >= ((Bit32u) ppr & 0xF0)))
977 ppr = task_priority;
978 else
979 ppr &= 0xF0;
980
981 return ppr;
982 }
983
set_tpr(Bit8u priority)984 void bx_local_apic_c::set_tpr(Bit8u priority)
985 {
986 if(priority < task_priority) {
987 task_priority = priority;
988 service_local_apic();
989 } else {
990 task_priority = priority;
991 }
992 }
993
get_apr(void)994 Bit8u bx_local_apic_c::get_apr(void)
995 {
996 Bit32u tpr = (task_priority >> 4) & 0xf;
997 int first_isr = highest_priority_int(isr);
998 if (first_isr < 0) first_isr = 0;
999 int first_irr = highest_priority_int(irr);
1000 if (first_irr < 0) first_irr = 0;
1001 Bit32u isrv = (first_isr >> 4) & 0xf;
1002 Bit32u irrv = (first_irr >> 4) & 0xf;
1003 Bit8u apr;
1004
1005 if((tpr >= irrv) && (tpr > isrv)) {
1006 apr = task_priority & 0xff;
1007 }
1008 else {
1009 apr = ((tpr & isrv) > irrv) ?(tpr & isrv) : irrv;
1010 apr <<= 4;
1011 }
1012
1013 BX_DEBUG(("apr = %d", apr));
1014
1015 return(Bit8u) apr;
1016 }
1017
is_focus(Bit8u vector)1018 bool bx_local_apic_c::is_focus(Bit8u vector)
1019 {
1020 if(focus_disable) return 0;
1021 return get_vector(irr, vector) || get_vector(isr, vector);
1022 }
1023
periodic_smf(void * this_ptr)1024 void bx_local_apic_c::periodic_smf(void *this_ptr)
1025 {
1026 bx_local_apic_c *class_ptr = (bx_local_apic_c *) this_ptr;
1027 class_ptr->periodic();
1028 }
1029
periodic(void)1030 void bx_local_apic_c::periodic(void)
1031 {
1032 if(!timer_active) {
1033 BX_ERROR(("bx_local_apic_c::periodic called, timer_active==0"));
1034 return;
1035 }
1036
1037 Bit32u timervec = lvt[APIC_LVT_TIMER];
1038
1039 // If timer is not masked, trigger interrupt
1040 if((timervec & 0x10000)==0) {
1041 trigger_irq(timervec & 0xff, APIC_EDGE_TRIGGERED);
1042 }
1043 else {
1044 BX_DEBUG(("local apic timer LVT masked"));
1045 }
1046
1047 // timer reached zero since the last call to periodic
1048 if(timervec & 0x20000) {
1049 // Periodic mode - reload timer values
1050 timer_current = timer_initial;
1051 timer_active = 1;
1052 ticksInitial = bx_pc_system.time_ticks(); // timer value when it started to count
1053 BX_DEBUG(("local apic timer(periodic) triggered int, reset counter to 0x%08x", timer_current));
1054 bx_pc_system.activate_timer_ticks(timer_handle,
1055 Bit64u(timer_initial) * Bit64u(timer_divide_factor), 0);
1056 }
1057 else {
1058 // one-shot mode
1059 timer_current = 0;
1060 timer_active = 0;
1061 BX_DEBUG(("local apic timer(one-shot) triggered int"));
1062 bx_pc_system.deactivate_timer(timer_handle);
1063 }
1064 }
1065
set_divide_configuration(Bit32u value)1066 void bx_local_apic_c::set_divide_configuration(Bit32u value)
1067 {
1068 BX_ASSERT(value == (value & 0x0b));
1069 // move bit 3 down to bit 0
1070 value = ((value & 8) >> 1) | (value & 3);
1071 BX_ASSERT(value >= 0 && value <= 7);
1072 timer_divide_factor = (value==7) ? 1 : (2 << value);
1073 BX_INFO(("set timer divide factor to %d", timer_divide_factor));
1074 }
1075
set_initial_timer_count(Bit32u value)1076 void bx_local_apic_c::set_initial_timer_count(Bit32u value)
1077 {
1078 #if BX_CPU_LEVEL >= 6
1079 Bit32u timervec = lvt[APIC_LVT_TIMER];
1080
1081 // in TSC-deadline mode writes to initial time count are ignored
1082 if (timervec & 0x40000) return;
1083 #endif
1084
1085 // If active before, deactivate the current timer before changing it.
1086 if(timer_active) {
1087 bx_pc_system.deactivate_timer(timer_handle);
1088 timer_active = 0;
1089 }
1090
1091 timer_initial = value;
1092 timer_current = 0;
1093
1094 if(timer_initial != 0) // terminate the counting if timer_initial = 0
1095 {
1096 // This should trigger the counter to start. If already started,
1097 // restart from the new start value.
1098 BX_DEBUG(("APIC: Initial Timer Count Register = %u", value));
1099 timer_current = timer_initial;
1100 timer_active = 1;
1101 ticksInitial = bx_pc_system.time_ticks(); // timer value when it started to count
1102 bx_pc_system.activate_timer_ticks(timer_handle,
1103 Bit64u(timer_initial) * Bit64u(timer_divide_factor), 0);
1104 }
1105 }
1106
get_current_timer_count(void)1107 Bit32u bx_local_apic_c::get_current_timer_count(void)
1108 {
1109 #if BX_CPU_LEVEL >= 6
1110 Bit32u timervec = lvt[APIC_LVT_TIMER];
1111
1112 // in TSC-deadline mode current timer count always reads 0
1113 if (timervec & 0x40000) return 0;
1114 #endif
1115
1116 if(timer_active==0) {
1117 return timer_current;
1118 } else {
1119 Bit64u delta64 = (bx_pc_system.time_ticks() - ticksInitial) / timer_divide_factor;
1120 Bit32u delta32 = (Bit32u) delta64;
1121 if(delta32 > timer_initial)
1122 BX_PANIC(("APIC: R(curr timer count): delta < initial"));
1123 timer_current = timer_initial - delta32;
1124 return timer_current;
1125 }
1126 }
1127
1128 #if BX_CPU_LEVEL >= 6
set_tsc_deadline(Bit64u deadline)1129 void bx_local_apic_c::set_tsc_deadline(Bit64u deadline)
1130 {
1131 Bit32u timervec = lvt[APIC_LVT_TIMER];
1132
1133 if ((timervec & 0x40000) == 0) {
1134 BX_ERROR(("APIC: TSC-Deadline timer is disabled"));
1135 return;
1136 }
1137
1138 // If active before, deactivate the current timer before changing it.
1139 if(timer_active) {
1140 bx_pc_system.deactivate_timer(timer_handle);
1141 timer_active = 0;
1142 }
1143
1144 ticksInitial = deadline;
1145 if (deadline != 0) {
1146 BX_DEBUG(("APIC: TSC-Deadline is set to " FMT_LL "d", deadline));
1147 Bit64u currtime = bx_pc_system.time_ticks();
1148 timer_active = 1;
1149 bx_pc_system.activate_timer_ticks(timer_handle, (deadline > currtime) ? (deadline - currtime) : 1 , 0);
1150 }
1151 }
1152
get_tsc_deadline(void)1153 Bit64u bx_local_apic_c::get_tsc_deadline(void)
1154 {
1155 Bit32u timervec = lvt[APIC_LVT_TIMER];
1156
1157 // read as zero if TSC-deadline timer is disabled
1158 if ((timervec & 0x40000) == 0) return 0;
1159
1160 return ticksInitial; /* also holds TSC-deadline value */
1161 }
1162 #endif
1163
1164 #if BX_SUPPORT_VMX >= 2
read_vmx_preemption_timer(void)1165 Bit32u bx_local_apic_c::read_vmx_preemption_timer(void)
1166 {
1167 Bit64u diff = (bx_pc_system.time_ticks() >> vmx_preemption_timer_rate) - (vmx_preemption_timer_initial >> vmx_preemption_timer_rate);
1168 if (vmx_preemption_timer_value < diff)
1169 return 0;
1170 else
1171 return vmx_preemption_timer_value - diff;
1172 }
1173
set_vmx_preemption_timer(Bit32u value)1174 void bx_local_apic_c::set_vmx_preemption_timer(Bit32u value)
1175 {
1176 vmx_preemption_timer_value = value;
1177 vmx_preemption_timer_initial = bx_pc_system.time_ticks();
1178 vmx_preemption_timer_fire = ((vmx_preemption_timer_initial >> vmx_preemption_timer_rate) + value) << vmx_preemption_timer_rate;
1179 BX_DEBUG(("VMX Preemption timer: value = %u, rate = %u, init = %u, fire = %u", value, vmx_preemption_timer_rate, vmx_preemption_timer_initial, vmx_preemption_timer_fire));
1180 bx_pc_system.activate_timer_ticks(vmx_timer_handle, vmx_preemption_timer_fire - vmx_preemption_timer_initial, 0);
1181 vmx_timer_active = 1;
1182 }
1183
deactivate_vmx_preemption_timer(void)1184 void bx_local_apic_c::deactivate_vmx_preemption_timer(void)
1185 {
1186 if (! vmx_timer_active) return;
1187 bx_pc_system.deactivate_timer(vmx_timer_handle);
1188 vmx_timer_active = 0;
1189 }
1190
1191 // Invoked when VMX preemption timer expired
vmx_preemption_timer_expired(void * this_ptr)1192 void bx_local_apic_c::vmx_preemption_timer_expired(void *this_ptr)
1193 {
1194 bx_local_apic_c *class_ptr = (bx_local_apic_c *) this_ptr;
1195 class_ptr->cpu->signal_event(BX_EVENT_VMX_PREEMPTION_TIMER_EXPIRED);
1196 class_ptr->deactivate_vmx_preemption_timer();
1197 }
1198 #endif
1199
1200 #if BX_SUPPORT_MONITOR_MWAIT
1201
set_mwaitx_timer(Bit32u value)1202 void bx_local_apic_c::set_mwaitx_timer(Bit32u value)
1203 {
1204 BX_DEBUG(("MWAITX timer: value = %u", value));
1205 bx_pc_system.activate_timer_ticks(mwaitx_timer_active, value, 0);
1206 mwaitx_timer_active = 1;
1207 }
1208
deactivate_mwaitx_timer(void)1209 void bx_local_apic_c::deactivate_mwaitx_timer(void)
1210 {
1211 if (! mwaitx_timer_active) return;
1212 bx_pc_system.deactivate_timer(mwaitx_timer_handle);
1213 mwaitx_timer_active = 0;
1214 }
1215
1216 // Invoked when MWAITX timer expired
mwaitx_timer_expired(void * this_ptr)1217 void bx_local_apic_c::mwaitx_timer_expired(void *this_ptr)
1218 {
1219 bx_local_apic_c *class_ptr = (bx_local_apic_c *) this_ptr;
1220 class_ptr->cpu->wakeup_monitor();
1221 class_ptr->deactivate_mwaitx_timer();
1222 }
1223
1224 #endif
1225
1226 #if BX_CPU_LEVEL >= 6
1227 // return false when x2apic is not supported/not readable
read_x2apic(unsigned index,Bit64u * val_64)1228 bool bx_local_apic_c::read_x2apic(unsigned index, Bit64u *val_64)
1229 {
1230 index = (index - 0x800) << 4;
1231
1232 switch(index) {
1233 // return full 32-bit lapic id
1234 case BX_LAPIC_ID:
1235 *val_64 = apic_id;
1236 break;
1237 case BX_LAPIC_LDR:
1238 *val_64 = ldr;
1239 break;
1240 // full 64-bit access to ICR
1241 case BX_LAPIC_ICR_LO:
1242 *val_64 = ((Bit64u) icr_lo) | (((Bit64u) icr_hi) << 32);
1243 break;
1244 // not supported/not readable in x2apic mode
1245 case BX_LAPIC_ARBITRATION_PRIORITY:
1246 case BX_LAPIC_DESTINATION_FORMAT:
1247 case BX_LAPIC_ICR_HI:
1248 case BX_LAPIC_EOI: // write only
1249 case BX_LAPIC_SELF_IPI: // write only
1250 return 0;
1251 // compatible to legacy lapic mode
1252 case BX_LAPIC_VERSION:
1253 case BX_LAPIC_TPR:
1254 case BX_LAPIC_PPR:
1255 case BX_LAPIC_SPURIOUS_VECTOR:
1256 case BX_LAPIC_ISR1:
1257 case BX_LAPIC_ISR2:
1258 case BX_LAPIC_ISR3:
1259 case BX_LAPIC_ISR4:
1260 case BX_LAPIC_ISR5:
1261 case BX_LAPIC_ISR6:
1262 case BX_LAPIC_ISR7:
1263 case BX_LAPIC_ISR8:
1264 case BX_LAPIC_TMR1:
1265 case BX_LAPIC_TMR2:
1266 case BX_LAPIC_TMR3:
1267 case BX_LAPIC_TMR4:
1268 case BX_LAPIC_TMR5:
1269 case BX_LAPIC_TMR6:
1270 case BX_LAPIC_TMR7:
1271 case BX_LAPIC_TMR8:
1272 case BX_LAPIC_IRR1:
1273 case BX_LAPIC_IRR2:
1274 case BX_LAPIC_IRR3:
1275 case BX_LAPIC_IRR4:
1276 case BX_LAPIC_IRR5:
1277 case BX_LAPIC_IRR6:
1278 case BX_LAPIC_IRR7:
1279 case BX_LAPIC_IRR8:
1280 case BX_LAPIC_ESR:
1281 case BX_LAPIC_LVT_TIMER:
1282 case BX_LAPIC_LVT_THERMAL:
1283 case BX_LAPIC_LVT_PERFMON:
1284 case BX_LAPIC_LVT_LINT0:
1285 case BX_LAPIC_LVT_LINT1:
1286 case BX_LAPIC_LVT_ERROR:
1287 case BX_LAPIC_LVT_CMCI:
1288 case BX_LAPIC_TIMER_INITIAL_COUNT:
1289 case BX_LAPIC_TIMER_CURRENT_COUNT:
1290 case BX_LAPIC_TIMER_DIVIDE_CFG:
1291 *val_64 = read_aligned(index);
1292 break;
1293 default:
1294 BX_ERROR(("read_x2apic: not supported apic register 0x%08x", index));
1295 return 0;
1296 }
1297
1298 return 1;
1299 }
1300
1301 // return false when x2apic is not supported/not writeable
write_x2apic(unsigned index,Bit32u val32_hi,Bit32u val32_lo)1302 bool bx_local_apic_c::write_x2apic(unsigned index, Bit32u val32_hi, Bit32u val32_lo)
1303 {
1304 index = (index - 0x800) << 4;
1305
1306 if (index != BX_LAPIC_ICR_LO) {
1307 // upper 32-bit are reserved for all x2apic MSRs except for the ICR
1308 if (val32_hi != 0)
1309 return 0;
1310 }
1311
1312 switch(index) {
1313 // read only/not available in x2apic mode
1314 case BX_LAPIC_ID:
1315 case BX_LAPIC_VERSION:
1316 case BX_LAPIC_ARBITRATION_PRIORITY:
1317 case BX_LAPIC_PPR:
1318 case BX_LAPIC_LDR:
1319 case BX_LAPIC_DESTINATION_FORMAT:
1320 case BX_LAPIC_ISR1:
1321 case BX_LAPIC_ISR2:
1322 case BX_LAPIC_ISR3:
1323 case BX_LAPIC_ISR4:
1324 case BX_LAPIC_ISR5:
1325 case BX_LAPIC_ISR6:
1326 case BX_LAPIC_ISR7:
1327 case BX_LAPIC_ISR8:
1328 case BX_LAPIC_TMR1:
1329 case BX_LAPIC_TMR2:
1330 case BX_LAPIC_TMR3:
1331 case BX_LAPIC_TMR4:
1332 case BX_LAPIC_TMR5:
1333 case BX_LAPIC_TMR6:
1334 case BX_LAPIC_TMR7:
1335 case BX_LAPIC_TMR8:
1336 case BX_LAPIC_IRR1:
1337 case BX_LAPIC_IRR2:
1338 case BX_LAPIC_IRR3:
1339 case BX_LAPIC_IRR4:
1340 case BX_LAPIC_IRR5:
1341 case BX_LAPIC_IRR6:
1342 case BX_LAPIC_IRR7:
1343 case BX_LAPIC_IRR8:
1344 case BX_LAPIC_ICR_HI:
1345 case BX_LAPIC_TIMER_CURRENT_COUNT:
1346 return 0;
1347 // send self ipi
1348 case BX_LAPIC_SELF_IPI:
1349 trigger_irq(val32_lo & 0xff, APIC_EDGE_TRIGGERED);
1350 return 1;
1351 case BX_LAPIC_ICR_LO:
1352 // handle full 64-bit write
1353 send_ipi(val32_hi, val32_lo);
1354 return 1;
1355 case BX_LAPIC_TPR:
1356 // handle reserved bits, only bits 0-7 are writeable
1357 if ((val32_lo & 0xffffff00) != 0)
1358 return 0;
1359 break; // use legacy write
1360 case BX_LAPIC_SPURIOUS_VECTOR:
1361 // handle reserved bits, only bits 0-8, 12 are writeable
1362 // we do not support directed EOI capability, so reserve bit 12 as well
1363 if ((val32_lo & 0xfffffe00) != 0)
1364 return 0;
1365 break; // use legacy write
1366 case BX_LAPIC_EOI:
1367 case BX_LAPIC_ESR:
1368 if (val32_lo != 0) return 0;
1369 break; // use legacy write
1370 case BX_LAPIC_LVT_TIMER:
1371 case BX_LAPIC_LVT_THERMAL:
1372 case BX_LAPIC_LVT_PERFMON:
1373 case BX_LAPIC_LVT_LINT0:
1374 case BX_LAPIC_LVT_LINT1:
1375 case BX_LAPIC_LVT_ERROR:
1376 case BX_LAPIC_LVT_CMCI:
1377 case BX_LAPIC_TIMER_INITIAL_COUNT:
1378 case BX_LAPIC_TIMER_DIVIDE_CFG:
1379 break; // use legacy write
1380 default:
1381 BX_ERROR(("write_x2apic: not supported apic register 0x%08x", index));
1382 return 0;
1383 }
1384
1385 write_aligned(index, val32_lo);
1386 return 1;
1387 }
1388 #endif
1389
register_state(bx_param_c * parent)1390 void bx_local_apic_c::register_state(bx_param_c *parent)
1391 {
1392 unsigned i;
1393 char name[6];
1394
1395 bx_list_c *lapic = new bx_list_c(parent, "local_apic");
1396
1397 BXRS_HEX_PARAM_SIMPLE(lapic, base_addr);
1398 BXRS_HEX_PARAM_SIMPLE(lapic, apic_id);
1399 BXRS_HEX_PARAM_SIMPLE(lapic, mode);
1400 BXRS_HEX_PARAM_SIMPLE(lapic, spurious_vector);
1401 BXRS_PARAM_BOOL(lapic, software_enabled, software_enabled);
1402 BXRS_PARAM_BOOL(lapic, focus_disable, focus_disable);
1403 BXRS_HEX_PARAM_SIMPLE(lapic, task_priority);
1404 BXRS_HEX_PARAM_SIMPLE(lapic, ldr);
1405 BXRS_HEX_PARAM_SIMPLE(lapic, dest_format);
1406
1407 for (i=0; i<8; i++) {
1408 sprintf(name, "isr%u", i);
1409 new bx_shadow_num_c(lapic, name, &isr[i], BASE_HEX);
1410
1411 sprintf(name, "tmr%u", i);
1412 new bx_shadow_num_c(lapic, name, &tmr[i], BASE_HEX);
1413
1414 sprintf(name, "irr%u", i);
1415 new bx_shadow_num_c(lapic, name, &irr[i], BASE_HEX);
1416 }
1417
1418 #if BX_CPU_LEVEL >= 6
1419 if (cpu->is_cpu_extension_supported(BX_ISA_XAPIC_EXT)) {
1420 BXRS_HEX_PARAM_SIMPLE(lapic, xapic_ext);
1421 for (i=0; i<8; i++) {
1422 sprintf(name, "ier%u", i);
1423 new bx_shadow_num_c(lapic, name, &ier[i], BASE_HEX);
1424 }
1425 }
1426 #endif
1427
1428 BXRS_HEX_PARAM_SIMPLE(lapic, error_status);
1429 BXRS_HEX_PARAM_SIMPLE(lapic, shadow_error_status);
1430 BXRS_HEX_PARAM_SIMPLE(lapic, icr_hi);
1431 BXRS_HEX_PARAM_SIMPLE(lapic, icr_lo);
1432
1433 for (i=0; i<APIC_LVT_ENTRIES; i++) {
1434 sprintf(name, "lvt%u", i);
1435 new bx_shadow_num_c(lapic, name, &lvt[i], BASE_HEX);
1436 }
1437
1438 BXRS_HEX_PARAM_SIMPLE(lapic, timer_initial);
1439 BXRS_HEX_PARAM_SIMPLE(lapic, timer_current);
1440 BXRS_HEX_PARAM_SIMPLE(lapic, timer_divconf);
1441 BXRS_DEC_PARAM_SIMPLE(lapic, timer_divide_factor);
1442 BXRS_DEC_PARAM_SIMPLE(lapic, timer_handle);
1443 BXRS_PARAM_BOOL(lapic, timer_active, timer_active);
1444 BXRS_HEX_PARAM_SIMPLE(lapic, ticksInitial);
1445
1446 #if BX_SUPPORT_VMX >= 2
1447 BXRS_DEC_PARAM_SIMPLE(lapic, vmx_timer_handle);
1448 BXRS_HEX_PARAM_SIMPLE(lapic, vmx_preemption_timer_initial);
1449 BXRS_HEX_PARAM_SIMPLE(lapic, vmx_preemption_timer_fire);
1450 BXRS_HEX_PARAM_SIMPLE(lapic, vmx_preemption_timer_value);
1451 BXRS_HEX_PARAM_SIMPLE(lapic, vmx_preemption_timer_rate);
1452 BXRS_PARAM_BOOL(lapic, vmx_timer_active, vmx_timer_active);
1453 #endif
1454
1455 #if BX_SUPPORT_MONITOR_MWAIT
1456 BXRS_DEC_PARAM_SIMPLE(lapic, mwaitx_timer_handle);
1457 BXRS_PARAM_BOOL(lapic, mwaitx_timer_active, mwaitx_timer_active);
1458 #endif
1459 }
1460
1461 #endif /* if BX_SUPPORT_APIC */
1462