3 #include "per_cpu_data.h"
11 class Apic : public Pm_object
14 static void init(bool resume = false) FIASCO_INIT_AND_PM;
15 Unsigned32 apic_id() const { return _id; }
16 Unsigned32 cpu_id() const { return _id >> 24; }
18 static Per_cpu<Static_object<Apic> > apic;
21 Apic(const Apic&) = delete;
22 Apic &operator = (Apic const &) = delete;
25 Unsigned32 _saved_apic_timer;
27 static void error_interrupt(Return_frame *regs)
28 asm ("apic_error_interrupt") FIASCO_FASTCALL;
32 static const Address io_base;
33 static Address phys_base;
34 static unsigned timer_divisor;
35 static unsigned frequency_khz;
36 static Unsigned64 scaler_us_to_apic;
43 APIC_tpri_mask = 0xFF,
46 APIC_ldr_mask = 0xFFul << 24,
57 APIC_timer_base_div = 0x2,
64 APIC_snd_pending = 1 << 12,
65 APIC_input_polarity = 1 << 13,
66 APIC_lvt_remote_irr = 1 << 14,
67 APIC_lvt_level_trigger = 1 << 15,
68 APIC_lvt_masked = 1 << 16,
69 APIC_lvt_timer_periodic = 1 << 17,
74 APIC_tdr_div_16 = 0x3,
75 APIC_tdr_div_32 = 0x8,
76 APIC_tdr_div_64 = 0x9,
77 APIC_tdr_div_128 = 0xA,
96 extern unsigned apic_spurious_interrupt_bug_cnt;
97 extern unsigned apic_spurious_interrupt_cnt;
98 extern unsigned apic_error_cnt;
101 //----------------------------------------------------------------------------
105 DEFINE_PER_CPU Per_cpu<Static_object<Apic> > Apic::apic;
108 Apic::Apic(Cpu_number cpu) : _id(get_id()) { register_pm(cpu); }
113 Apic::cpu() { return *Cpu::boot_cpu(); }
115 // FIXME: workaround for missing lambdas in gcc < 4.5
120 By_id(Unsigned32 p) : p(p) {}
121 bool operator () (Apic const *a) const { return a && a->apic_id() == p; }
127 Apic::find_cpu(Unsigned32 phys_id)
129 return apic.find_cpu(By_id(phys_id));
133 Apic::pm_on_suspend(Cpu_number)
135 _saved_apic_timer = timer_reg_read();
138 //----------------------------------------------------------------------------
139 IMPLEMENTATION [!mp]:
142 Apic::pm_on_resume(Cpu_number)
145 timer_reg_write(_saved_apic_timer);
148 //----------------------------------------------------------------------------
152 Apic::pm_on_resume(Cpu_number cpu)
154 if (cpu == Cpu_number::boot_cpu())
158 timer_reg_write(_saved_apic_timer);
162 //----------------------------------------------------------------------------
163 IMPLEMENTATION[ia32]:
167 Apic::us_to_apic(Unsigned64 us)
169 Unsigned32 apic, dummy1, dummy2;
170 asm ("movl %%edx, %%ecx \n\t"
172 "movl %%ecx, %%eax \n\t"
173 "movl %%edx, %%ecx \n\t"
175 "addl %%ecx, %%eax \n\t"
176 "shll $11, %%eax \n\t"
177 :"=a" (apic), "=d" (dummy1), "=&c" (dummy2)
178 : "A" (us), "g" (scaler_us_to_apic)
183 IMPLEMENTATION[amd64]:
187 Apic::us_to_apic(Unsigned64 us)
189 Unsigned32 apic, dummy;
191 "shrq $21,%%rax \n\t"
192 :"=a"(apic), "=d"(dummy)
193 :"a"(us), "g"(scaler_us_to_apic)
198 IMPLEMENTATION[ia32,amd64]:
207 #include "cpu_lock.h"
208 #include "entry_frame.h"
213 #include "lock_guard.h"
215 #include "processor.h"
220 unsigned apic_spurious_interrupt_bug_cnt;
221 unsigned apic_spurious_interrupt_cnt;
222 unsigned apic_error_cnt;
223 Address apic_io_base;
227 const Address Apic::io_base = Mem_layout::Local_apic_page;
228 Address Apic::phys_base;
229 unsigned Apic::timer_divisor = 1;
230 unsigned Apic::frequency_khz;
231 Unsigned64 Apic::scaler_us_to_apic;
233 int ignore_invalid_apic_reg_access;
239 return reg_read(APIC_id) & 0xff000000;
242 PRIVATE static inline
246 return reg_read(APIC_lvr) & 0xFF;
249 PRIVATE static inline NOEXPORT
251 Apic::is_integrated()
253 return reg_read(APIC_lvr) & 0xF0;
256 PRIVATE static inline NOEXPORT
258 Apic::get_max_lvt_local()
260 return ((reg_read(APIC_lvr) >> 16) & 0xFF);
263 PRIVATE static inline NOEXPORT
265 Apic::get_num_errors()
267 reg_write(APIC_esr, 0);
268 return reg_read(APIC_esr);
271 PRIVATE static inline NOEXPORT
273 Apic::clear_num_errors()
275 reg_write(APIC_esr, 0);
276 reg_write(APIC_esr, 0);
281 Apic::get_frequency_khz()
283 return frequency_khz;
288 Apic::reg_read(unsigned reg)
291 /* assembly-encoded to match the Jailhouse hypervisor MMIO parser support */
292 void *address = (void*)(/*(Unsigned32*)*/(io_base + reg));
293 asm volatile("mov (%1),%0" : "=r" (val) : "r" (address));
299 Apic::reg_write(unsigned reg, Unsigned32 val)
301 /* assembly-encoded to match the Jailhouse hypervisor MMIO parser support */
302 void *address = (void*)(/*(Unsigned32*)*/(io_base + reg));
303 asm volatile("mov %0,(%1)" : : "r" (val), "r" (address));
308 Apic::reg_delivery_mode(Unsigned32 val)
310 return (val >> 8) & 7;
315 Apic::reg_lvt_vector(Unsigned32 val)
322 Apic::timer_reg_read()
324 return reg_read(APIC_tmcct);
329 Apic::timer_reg_read_initial()
331 return reg_read(APIC_tmict);
336 Apic::timer_reg_write(Unsigned32 val)
338 reg_read(APIC_tmict);
339 reg_write(APIC_tmict, val);
342 PUBLIC static inline NEEDS["cpu.h"]
344 Apic::apic_page_phys()
345 { return Cpu::rdmsr(APIC_base_msr) & 0xfffff000; }
347 // set the global pagetable entry for the Local APIC device registers
349 static FIASCO_INIT_AND_PM
351 Apic::map_apic_page()
354 Address base = apic_page_phys();
355 // We should not change the physical address of the Local APIC page if
356 // possible since some versions of VMware would complain about a
357 // non-implemented feature
358 Kmem::map_phys_page(base, Mem_layout::Local_apic_page,
361 Kip::k()->add_mem_region(Mem_desc(base, base + Config::PAGE_SIZE - 1, Mem_desc::Reserved));
366 // check CPU type if APIC could be present
367 static FIASCO_INIT_AND_PM
371 if (!cpu().can_wrmsr() || !(cpu().features() & FEAT_TSC))
374 if (cpu().vendor() == Cpu::Vendor_intel)
376 if (cpu().family() == 15)
378 if (cpu().family() >= 6)
381 if (cpu().vendor() == Cpu::Vendor_amd && cpu().family() >= 6)
387 // test if APIC present
392 return cpu().features() & FEAT_APIC;
397 Apic::timer_enable_irq()
401 tmp_val = reg_read(APIC_lvtt);
402 tmp_val &= ~(APIC_lvt_masked);
403 reg_write(APIC_lvtt, tmp_val);
408 Apic::timer_disable_irq()
412 tmp_val = reg_read(APIC_lvtt);
413 tmp_val |= APIC_lvt_masked;
414 reg_write(APIC_lvtt, tmp_val);
419 Apic::timer_is_irq_enabled()
421 return ~reg_read(APIC_lvtt) & APIC_lvt_masked;
426 Apic::timer_set_periodic()
428 Unsigned32 tmp_val = reg_read(APIC_lvtt);
429 tmp_val |= APIC_lvt_timer_periodic;
430 reg_write(APIC_lvtt, tmp_val);
435 Apic::timer_set_one_shot()
437 Unsigned32 tmp_val = reg_read(APIC_lvtt);
438 tmp_val &= ~APIC_lvt_timer_periodic;
439 reg_write(APIC_lvtt, tmp_val);
444 Apic::timer_assign_irq_vector(unsigned vector)
446 Unsigned32 tmp_val = reg_read(APIC_lvtt);
447 tmp_val &= 0xffffff00;
449 reg_write(APIC_lvtt, tmp_val);
457 reg_write(APIC_eoi, 0);
462 Apic::timer_set_divisor(unsigned newdiv)
467 Unsigned32 tmp_value;
469 static int divisor_tab[8] =
471 APIC_tdr_div_1, APIC_tdr_div_2, APIC_tdr_div_4, APIC_tdr_div_8,
472 APIC_tdr_div_16, APIC_tdr_div_32, APIC_tdr_div_64, APIC_tdr_div_128
481 printf("bad APIC divisor %u\n", newdiv);
484 div = divisor_tab[i];
492 timer_divisor = newdiv;
493 tmp_value = reg_read(APIC_tdcr);
496 reg_write(APIC_tdcr, tmp_value);
504 return is_integrated() ? get_max_lvt_local() : 2;
511 return (present && (get_max_lvt() >= 4));
518 return (present && (get_max_lvt() >= 5));
521 // check if APIC is working (check timer functionality)
522 static FIASCO_INIT_AND_PM
524 Apic::check_working()
526 Unsigned64 tsc_until;
529 timer_set_divisor(1);
530 timer_reg_write(0x10000000);
532 tsc_until = Cpu::rdtsc() + 0x400; // we only have to wait for one bus cycle
536 if (timer_reg_read() != 0x10000000)
538 } while (Cpu::rdtsc() < tsc_until);
543 static FIASCO_INIT_CPU_AND_PM
549 tmp_val = reg_read(APIC_spiv);
550 tmp_val |= (1<<8); // enable APIC
551 tmp_val &= ~(1<<9); // enable Focus Processor Checking
553 tmp_val |= APIC_IRQ_BASE + 0xf; // Set spurious IRQ vector to 0x3f
554 // bit 0..3 are hardwired to 1 on PPro!
555 reg_write(APIC_spiv, tmp_val);
558 PUBLIC static inline NEEDS[Apic::reg_write]
560 Apic::tpr(unsigned prio)
561 { reg_write(APIC_tpr, prio); }
563 PUBLIC static inline NEEDS[Apic::reg_read]
566 { return reg_read(APIC_tpr); }
568 static FIASCO_INIT_CPU_AND_PM
572 reg_write(APIC_tpr, 0);
575 // activate APIC error interrupt
576 static FIASCO_INIT_CPU_AND_PM
578 Apic::enable_errors()
582 Unsigned32 tmp_val, before, after;
584 if (get_max_lvt() > 3)
586 before = get_num_errors();
588 tmp_val = reg_read(APIC_lvterr);
589 tmp_val &= 0xfffeff00; // unmask error IRQ vector
590 tmp_val |= APIC_IRQ_BASE + 3; // Set error IRQ vector to 0x63
591 reg_write(APIC_lvterr, tmp_val);
593 if (get_max_lvt() > 3)
595 after = get_num_errors();
596 printf("APIC ESR value before/after enabling: %08x/%08x\n",
601 // activate APIC after activating by MSR was successful
602 // see "Intel Architecture Software Developer's Manual,
603 // Volume 3: System Programming Guide, Appendix E"
604 static FIASCO_INIT_AND_PM
606 Apic::route_pic_through_apic()
609 auto guard = lock_guard(cpu_lock);
611 // mask 8259 interrupts
612 Unsigned16 old_irqs = Pic::disable_all_save();
614 // set LINT0 to ExtINT, edge triggered
615 tmp_val = reg_read(APIC_lvt0);
616 tmp_val &= 0xfffe5800;
617 tmp_val |= 0x00000700;
618 reg_write(APIC_lvt0, tmp_val);
620 // set LINT1 to NMI, edge triggered
621 tmp_val = reg_read(APIC_lvt1);
622 tmp_val &= 0xfffe5800;
623 tmp_val |= 0x00000400;
624 reg_write(APIC_lvt1, tmp_val);
626 // unmask 8259 interrupts
627 Pic::restore_all(old_irqs);
629 printf("APIC was disabled --- routing PIC through APIC\n");
632 static FIASCO_INIT_CPU_AND_PM
636 auto guard = lock_guard(cpu_lock);
638 // mask timer interrupt and set vector to _not_ invalid value
639 reg_write(APIC_lvtt, reg_read(APIC_lvtt) | APIC_lvt_masked | 0xff);
642 // mask performance interrupt and set vector to a valid value
643 reg_write(APIC_lvtpc, reg_read(APIC_lvtpc) | APIC_lvt_masked | 0xff);
646 // mask thermal sensor interrupt and set vector to a valid value
647 reg_write(APIC_lvtthmr, reg_read(APIC_lvtthmr) | APIC_lvt_masked | 0xff);
650 // give us a hint if we have an APIC but it is disabled
653 Apic::test_present_but_disabled()
658 Unsigned64 msr = Cpu::rdmsr(APIC_base_msr);
659 return ((msr & 0xffffff000ULL) == 0xfee00000ULL);
662 // activate APIC by writing to appropriate MSR
663 static FIASCO_INIT_CPU_AND_PM
665 Apic::activate_by_msr()
669 msr = Cpu::rdmsr(APIC_base_msr);
670 phys_base = msr & 0xfffff000;
672 Cpu::wrmsr(msr, APIC_base_msr);
674 // now the CPU feature flags may have changed
675 cpu().update_features_info();
678 // check if we still receive interrupts after we changed the IRQ routing
679 PUBLIC static FIASCO_INIT_CPU
681 Apic::check_still_getting_interrupts()
686 Unsigned64 tsc_until;
687 Cpu_time clock_start = Kip::k()->clock;
689 tsc_until = Cpu::rdtsc();
690 tsc_until += 0x01000000; // > 10 Mio cycles should be sufficient until
691 // we have processors with more than 10 GHz
694 // kernel clock by timer interrupt updated?
695 if (Kip::k()->clock != clock_start)
698 } while (Cpu::rdtsc() < tsc_until);
716 reg_write(APIC_lvtpc, 0x400);
719 static FIASCO_INIT_CPU_AND_PM
721 Apic::calibrate_timer()
723 const unsigned calibrate_time = 50;
724 Unsigned32 count, tt1, tt2, result, dummy;
725 Unsigned32 runs = 0, frequency_ok;
732 timer_set_divisor(1);
733 timer_reg_write(1000000000);
736 auto guard = lock_guard(cpu_lock);
738 Pit::setup_channel2_to_20hz();
742 tt1 = timer_reg_read();
747 while ((Io::in8(0x61) & 0x20) == 0);
748 tt2 = timer_reg_read();
751 result = (tt1 - tt2) * timer_divisor;
758 :"=a" (frequency_khz), "=d" (dummy)
759 : "r" (calibrate_time), "a" (result), "d" (0));
761 frequency_ok = (frequency_khz < (1000<<11));
763 while (++runs < 10 && !frequency_ok);
766 panic("APIC frequency too high, adapt Apic::scaler_us_to_apic");
768 Kip::k()->frequency_bus = frequency_khz;
769 scaler_us_to_apic = Cpu::muldiv(1<<21, frequency_khz, 1000);
774 Apic::error_interrupt(Return_frame *regs)
776 Unsigned32 err1, err2;
778 // we are entering with disabled interrupts
779 err1 = Apic::get_num_errors();
780 Apic::clear_num_errors();
781 err2 = Apic::get_num_errors();
786 if (err1 == 0x80 || err2 == 0x80)
788 // ignore possible invalid access which may happen in
789 // jdb::do_dump_memory()
790 if (ignore_invalid_apic_reg_access)
793 printf("CPU%u: APIC invalid register access error at " L4_PTR_FMT "\n",
794 cxx::int_value<Cpu_number>(current_cpu()), regs->ip());
799 printf("CPU%u: APIC error %08x(%08x)\n",
800 cxx::int_value<Cpu_number>(current_cpu()), err1, err2);
803 // deactivate APIC by writing to appropriate MSR
813 val = reg_read(APIC_spiv);
815 reg_write(APIC_spiv, val);
817 val = Cpu::rdmsr(APIC_base_msr);
819 Cpu::wrmsr(val, APIC_base_msr);
822 PRIVATE static FIASCO_INIT_CPU_AND_PM
827 timer_set_divisor(1);
835 printf("Local APIC[%02x]: version=%02x max_lvt=%d\n",
836 get_id() >> 24, get_version(), get_max_lvt());
841 Apic::init(bool resume)
844 // FIXME: reset cached CPU features, we should add a special function
847 cpu().update_features_info();
849 was_present = present = test_present();
853 good_cpu = test_cpu();
855 if (good_cpu && Config::apic)
857 // activate; this could lead an disabled APIC to appear
858 // set base address of I/O registers to be able to access the registers
860 present = test_present();
867 // initialize if available
870 // map the Local APIC device registers
874 // set some interrupt vectors to appropriate values
877 // initialize APIC_spiv register
880 // initialize task-priority register
883 // test if local timer counts down
884 if ((present = check_working()))
887 // APIC _was_ not present before writing to msr so we have
888 // to set APIC_lvt0 and APIC_lvt1 to appropriate values
889 route_pic_through_apic();
894 panic("Local APIC not found");
898 apic_io_base = Mem_layout::Local_apic_page;