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)
290 return *((volatile Unsigned32*)(io_base + reg));
295 Apic::reg_write(unsigned reg, Unsigned32 val)
297 *((volatile Unsigned32*)(io_base + reg)) = val;
302 Apic::reg_delivery_mode(Unsigned32 val)
304 return (val >> 8) & 7;
309 Apic::reg_lvt_vector(Unsigned32 val)
316 Apic::timer_reg_read()
318 return reg_read(APIC_tmcct);
323 Apic::timer_reg_read_initial()
325 return reg_read(APIC_tmict);
330 Apic::timer_reg_write(Unsigned32 val)
332 reg_read(APIC_tmict);
333 reg_write(APIC_tmict, val);
336 PUBLIC static inline NEEDS["cpu.h"]
338 Apic::apic_page_phys()
339 { return Cpu::rdmsr(APIC_base_msr) & 0xfffff000; }
341 // set the global pagetable entry for the Local APIC device registers
343 static FIASCO_INIT_AND_PM
345 Apic::map_apic_page()
348 Address base = apic_page_phys();
349 // We should not change the physical address of the Local APIC page if
350 // possible since some versions of VMware would complain about a
351 // non-implemented feature
352 Kmem::map_phys_page(base, Mem_layout::Local_apic_page,
355 Kip::k()->add_mem_region(Mem_desc(base, base + Config::PAGE_SIZE - 1, Mem_desc::Reserved));
360 // check CPU type if APIC could be present
361 static FIASCO_INIT_AND_PM
365 if (!cpu().can_wrmsr() || !(cpu().features() & FEAT_TSC))
368 if (cpu().vendor() == Cpu::Vendor_intel)
370 if (cpu().family() == 15)
372 if (cpu().family() >= 6)
375 if (cpu().vendor() == Cpu::Vendor_amd && cpu().family() >= 6)
381 // test if APIC present
386 return cpu().features() & FEAT_APIC;
391 Apic::timer_enable_irq()
395 tmp_val = reg_read(APIC_lvtt);
396 tmp_val &= ~(APIC_lvt_masked);
397 reg_write(APIC_lvtt, tmp_val);
402 Apic::timer_disable_irq()
406 tmp_val = reg_read(APIC_lvtt);
407 tmp_val |= APIC_lvt_masked;
408 reg_write(APIC_lvtt, tmp_val);
413 Apic::timer_is_irq_enabled()
415 return ~reg_read(APIC_lvtt) & APIC_lvt_masked;
420 Apic::timer_set_periodic()
422 Unsigned32 tmp_val = reg_read(APIC_lvtt);
423 tmp_val |= APIC_lvt_timer_periodic;
424 reg_write(APIC_lvtt, tmp_val);
429 Apic::timer_set_one_shot()
431 Unsigned32 tmp_val = reg_read(APIC_lvtt);
432 tmp_val &= ~APIC_lvt_timer_periodic;
433 reg_write(APIC_lvtt, tmp_val);
438 Apic::timer_assign_irq_vector(unsigned vector)
440 Unsigned32 tmp_val = reg_read(APIC_lvtt);
441 tmp_val &= 0xffffff00;
443 reg_write(APIC_lvtt, tmp_val);
451 reg_write(APIC_eoi, 0);
456 Apic::timer_set_divisor(unsigned newdiv)
461 Unsigned32 tmp_value;
463 static int divisor_tab[8] =
465 APIC_tdr_div_1, APIC_tdr_div_2, APIC_tdr_div_4, APIC_tdr_div_8,
466 APIC_tdr_div_16, APIC_tdr_div_32, APIC_tdr_div_64, APIC_tdr_div_128
475 printf("bad APIC divisor %u\n", newdiv);
478 div = divisor_tab[i];
486 timer_divisor = newdiv;
487 tmp_value = reg_read(APIC_tdcr);
490 reg_write(APIC_tdcr, tmp_value);
498 return is_integrated() ? get_max_lvt_local() : 2;
505 return (present && (get_max_lvt() >= 4));
512 return (present && (get_max_lvt() >= 5));
515 // check if APIC is working (check timer functionality)
516 static FIASCO_INIT_AND_PM
518 Apic::check_working()
520 Unsigned64 tsc_until;
523 timer_set_divisor(1);
524 timer_reg_write(0x10000000);
526 tsc_until = Cpu::rdtsc() + 0x400; // we only have to wait for one bus cycle
530 if (timer_reg_read() != 0x10000000)
532 } while (Cpu::rdtsc() < tsc_until);
537 static FIASCO_INIT_CPU_AND_PM
543 tmp_val = reg_read(APIC_spiv);
544 tmp_val |= (1<<8); // enable APIC
545 tmp_val &= ~(1<<9); // enable Focus Processor Checking
547 tmp_val |= APIC_IRQ_BASE + 0xf; // Set spurious IRQ vector to 0x3f
548 // bit 0..3 are hardwired to 1 on PPro!
549 reg_write(APIC_spiv, tmp_val);
552 PUBLIC static inline NEEDS[Apic::reg_write]
554 Apic::tpr(unsigned prio)
555 { reg_write(APIC_tpr, prio); }
557 PUBLIC static inline NEEDS[Apic::reg_read]
560 { return reg_read(APIC_tpr); }
562 static FIASCO_INIT_CPU_AND_PM
566 reg_write(APIC_tpr, 0);
569 // activate APIC error interrupt
570 static FIASCO_INIT_CPU_AND_PM
572 Apic::enable_errors()
576 Unsigned32 tmp_val, before, after;
578 if (get_max_lvt() > 3)
580 before = get_num_errors();
582 tmp_val = reg_read(APIC_lvterr);
583 tmp_val &= 0xfffeff00; // unmask error IRQ vector
584 tmp_val |= APIC_IRQ_BASE + 3; // Set error IRQ vector to 0x63
585 reg_write(APIC_lvterr, tmp_val);
587 if (get_max_lvt() > 3)
589 after = get_num_errors();
590 printf("APIC ESR value before/after enabling: %08x/%08x\n",
595 // activate APIC after activating by MSR was successful
596 // see "Intel Architecture Software Developer's Manual,
597 // Volume 3: System Programming Guide, Appendix E"
598 static FIASCO_INIT_AND_PM
600 Apic::route_pic_through_apic()
603 auto guard = lock_guard(cpu_lock);
605 // mask 8259 interrupts
606 Unsigned16 old_irqs = Pic::disable_all_save();
608 // set LINT0 to ExtINT, edge triggered
609 tmp_val = reg_read(APIC_lvt0);
610 tmp_val &= 0xfffe5800;
611 tmp_val |= 0x00000700;
612 reg_write(APIC_lvt0, tmp_val);
614 // set LINT1 to NMI, edge triggered
615 tmp_val = reg_read(APIC_lvt1);
616 tmp_val &= 0xfffe5800;
617 tmp_val |= 0x00000400;
618 reg_write(APIC_lvt1, tmp_val);
620 // unmask 8259 interrupts
621 Pic::restore_all(old_irqs);
623 printf("APIC was disabled --- routing PIC through APIC\n");
626 static FIASCO_INIT_CPU_AND_PM
630 auto guard = lock_guard(cpu_lock);
632 // mask timer interrupt and set vector to _not_ invalid value
633 reg_write(APIC_lvtt, reg_read(APIC_lvtt) | APIC_lvt_masked | 0xff);
636 // mask performance interrupt and set vector to a valid value
637 reg_write(APIC_lvtpc, reg_read(APIC_lvtpc) | APIC_lvt_masked | 0xff);
640 // mask thermal sensor interrupt and set vector to a valid value
641 reg_write(APIC_lvtthmr, reg_read(APIC_lvtthmr) | APIC_lvt_masked | 0xff);
644 // give us a hint if we have an APIC but it is disabled
647 Apic::test_present_but_disabled()
652 Unsigned64 msr = Cpu::rdmsr(APIC_base_msr);
653 return ((msr & 0xffffff000ULL) == 0xfee00000ULL);
656 // activate APIC by writing to appropriate MSR
657 static FIASCO_INIT_CPU_AND_PM
659 Apic::activate_by_msr()
663 msr = Cpu::rdmsr(APIC_base_msr);
664 phys_base = msr & 0xfffff000;
666 Cpu::wrmsr(msr, APIC_base_msr);
668 // now the CPU feature flags may have changed
669 cpu().update_features_info();
672 // check if we still receive interrupts after we changed the IRQ routing
673 PUBLIC static FIASCO_INIT_CPU
675 Apic::check_still_getting_interrupts()
680 Unsigned64 tsc_until;
681 Cpu_time clock_start = Kip::k()->clock;
683 tsc_until = Cpu::rdtsc();
684 tsc_until += 0x01000000; // > 10 Mio cycles should be sufficient until
685 // we have processors with more than 10 GHz
688 // kernel clock by timer interrupt updated?
689 if (Kip::k()->clock != clock_start)
692 } while (Cpu::rdtsc() < tsc_until);
710 reg_write(APIC_lvtpc, 0x400);
713 static FIASCO_INIT_CPU_AND_PM
715 Apic::calibrate_timer()
717 const unsigned calibrate_time = 50;
718 Unsigned32 count, tt1, tt2, result, dummy;
719 Unsigned32 runs = 0, frequency_ok;
726 timer_set_divisor(1);
727 timer_reg_write(1000000000);
730 auto guard = lock_guard(cpu_lock);
732 Pit::setup_channel2_to_20hz();
736 tt1 = timer_reg_read();
741 while ((Io::in8(0x61) & 0x20) == 0);
742 tt2 = timer_reg_read();
745 result = (tt1 - tt2) * timer_divisor;
752 :"=a" (frequency_khz), "=d" (dummy)
753 : "r" (calibrate_time), "a" (result), "d" (0));
755 frequency_ok = (frequency_khz < (1000<<11));
757 while (++runs < 10 && !frequency_ok);
760 panic("APIC frequency too high, adapt Apic::scaler_us_to_apic");
762 Kip::k()->frequency_bus = frequency_khz;
763 scaler_us_to_apic = Cpu::muldiv(1<<21, frequency_khz, 1000);
768 Apic::error_interrupt(Return_frame *regs)
770 Unsigned32 err1, err2;
772 // we are entering with disabled interrupts
773 err1 = Apic::get_num_errors();
774 Apic::clear_num_errors();
775 err2 = Apic::get_num_errors();
780 if (err1 == 0x80 || err2 == 0x80)
782 // ignore possible invalid access which may happen in
783 // jdb::do_dump_memory()
784 if (ignore_invalid_apic_reg_access)
787 printf("CPU%u: APIC invalid register access error at " L4_PTR_FMT "\n",
788 cxx::int_value<Cpu_number>(current_cpu()), regs->ip());
793 printf("CPU%u: APIC error %08x(%08x)\n",
794 cxx::int_value<Cpu_number>(current_cpu()), err1, err2);
797 // deactivate APIC by writing to appropriate MSR
807 val = reg_read(APIC_spiv);
809 reg_write(APIC_spiv, val);
811 val = Cpu::rdmsr(APIC_base_msr);
813 Cpu::wrmsr(val, APIC_base_msr);
816 PRIVATE static FIASCO_INIT_CPU_AND_PM
821 timer_set_divisor(1);
829 printf("Local APIC[%02x]: version=%02x max_lvt=%d\n",
830 get_id() >> 24, get_version(), get_max_lvt());
835 Apic::init(bool resume)
838 // FIXME: reset cached CPU features, we should add a special function
841 cpu().update_features_info();
843 was_present = present = test_present();
847 good_cpu = test_cpu();
849 if (good_cpu && Config::apic)
851 // activate; this could lead an disabled APIC to appear
852 // set base address of I/O registers to be able to access the registers
854 present = test_present();
861 // initialize if available
864 // map the Local APIC device registers
868 // set some interrupt vectors to appropriate values
871 // initialize APIC_spiv register
874 // initialize task-priority register
877 // test if local timer counts down
878 if ((present = check_working()))
881 // APIC _was_ not present before writing to msr so we have
882 // to set APIC_lvt0 and APIC_lvt1 to appropriate values
883 route_pic_through_apic();
888 panic("Local APIC not found");
892 apic_io_base = Mem_layout::Local_apic_page;