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