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 asm volatile ("mov %1,%0\n" : "=b" (val) : "m" (*(Unsigned32*)(io_base + reg)) : "memory");
297 Apic::reg_write(unsigned reg, Unsigned32 val)
299 asm volatile ("mov %1,%0\n" : "=m" (*(Unsigned32*)(io_base + reg)) : "b" (val) : "memory");
304 Apic::reg_delivery_mode(Unsigned32 val)
306 return (val >> 8) & 7;
311 Apic::reg_lvt_vector(Unsigned32 val)
318 Apic::timer_reg_read()
320 return reg_read(APIC_tmcct);
325 Apic::timer_reg_read_initial()
327 return reg_read(APIC_tmict);
332 Apic::timer_reg_write(Unsigned32 val)
334 reg_read(APIC_tmict);
335 reg_write(APIC_tmict, val);
338 PUBLIC static inline NEEDS["cpu.h"]
340 Apic::apic_page_phys()
341 { return Cpu::rdmsr(APIC_base_msr) & 0xfffff000; }
343 // set the global pagetable entry for the Local APIC device registers
345 static FIASCO_INIT_AND_PM
347 Apic::map_apic_page()
350 Address base = apic_page_phys();
351 // We should not change the physical address of the Local APIC page if
352 // possible since some versions of VMware would complain about a
353 // non-implemented feature
354 Kmem::map_phys_page(base, Mem_layout::Local_apic_page,
357 Kip::k()->add_mem_region(Mem_desc(base, base + Config::PAGE_SIZE - 1, Mem_desc::Reserved));
362 // check CPU type if APIC could be present
363 static FIASCO_INIT_AND_PM
367 if (!cpu().can_wrmsr() || !(cpu().features() & FEAT_TSC))
370 if (cpu().vendor() == Cpu::Vendor_intel)
372 if (cpu().family() == 15)
374 if (cpu().family() >= 6)
377 if (cpu().vendor() == Cpu::Vendor_amd && cpu().family() >= 6)
383 // test if APIC present
388 return cpu().features() & FEAT_APIC;
393 Apic::timer_enable_irq()
397 tmp_val = reg_read(APIC_lvtt);
398 tmp_val &= ~(APIC_lvt_masked);
399 reg_write(APIC_lvtt, tmp_val);
404 Apic::timer_disable_irq()
408 tmp_val = reg_read(APIC_lvtt);
409 tmp_val |= APIC_lvt_masked;
410 reg_write(APIC_lvtt, tmp_val);
415 Apic::timer_is_irq_enabled()
417 return ~reg_read(APIC_lvtt) & APIC_lvt_masked;
422 Apic::timer_set_periodic()
424 Unsigned32 tmp_val = reg_read(APIC_lvtt);
425 tmp_val |= APIC_lvt_timer_periodic;
426 reg_write(APIC_lvtt, tmp_val);
431 Apic::timer_set_one_shot()
433 Unsigned32 tmp_val = reg_read(APIC_lvtt);
434 tmp_val &= ~APIC_lvt_timer_periodic;
435 reg_write(APIC_lvtt, tmp_val);
440 Apic::timer_assign_irq_vector(unsigned vector)
442 Unsigned32 tmp_val = reg_read(APIC_lvtt);
443 tmp_val &= 0xffffff00;
445 reg_write(APIC_lvtt, tmp_val);
453 reg_write(APIC_eoi, 0);
458 Apic::timer_set_divisor(unsigned newdiv)
463 Unsigned32 tmp_value;
465 static int divisor_tab[8] =
467 APIC_tdr_div_1, APIC_tdr_div_2, APIC_tdr_div_4, APIC_tdr_div_8,
468 APIC_tdr_div_16, APIC_tdr_div_32, APIC_tdr_div_64, APIC_tdr_div_128
477 printf("bad APIC divisor %u\n", newdiv);
480 div = divisor_tab[i];
488 timer_divisor = newdiv;
489 tmp_value = reg_read(APIC_tdcr);
492 reg_write(APIC_tdcr, tmp_value);
500 return is_integrated() ? get_max_lvt_local() : 2;
507 return (present && (get_max_lvt() >= 4));
514 return (present && (get_max_lvt() >= 5));
517 // check if APIC is working (check timer functionality)
518 static FIASCO_INIT_AND_PM
520 Apic::check_working()
522 Unsigned64 tsc_until;
525 timer_set_divisor(1);
526 timer_reg_write(0x10000000);
528 tsc_until = Cpu::rdtsc() + 0x400; // we only have to wait for one bus cycle
532 if (timer_reg_read() != 0x10000000)
534 } while (Cpu::rdtsc() < tsc_until);
539 static FIASCO_INIT_CPU_AND_PM
545 tmp_val = reg_read(APIC_spiv);
546 tmp_val |= (1<<8); // enable APIC
547 tmp_val &= ~(1<<9); // enable Focus Processor Checking
549 tmp_val |= APIC_IRQ_BASE + 0xf; // Set spurious IRQ vector to 0x3f
550 // bit 0..3 are hardwired to 1 on PPro!
551 reg_write(APIC_spiv, tmp_val);
554 PUBLIC static inline NEEDS[Apic::reg_write]
556 Apic::tpr(unsigned prio)
557 { reg_write(APIC_tpr, prio); }
559 PUBLIC static inline NEEDS[Apic::reg_read]
562 { return reg_read(APIC_tpr); }
564 static FIASCO_INIT_CPU_AND_PM
568 reg_write(APIC_tpr, 0);
571 // activate APIC error interrupt
572 static FIASCO_INIT_CPU_AND_PM
574 Apic::enable_errors()
578 Unsigned32 tmp_val, before, after;
580 if (get_max_lvt() > 3)
582 before = get_num_errors();
584 tmp_val = reg_read(APIC_lvterr);
585 tmp_val &= 0xfffeff00; // unmask error IRQ vector
586 tmp_val |= APIC_IRQ_BASE + 3; // Set error IRQ vector to 0x63
587 reg_write(APIC_lvterr, tmp_val);
589 if (get_max_lvt() > 3)
591 after = get_num_errors();
592 printf("APIC ESR value before/after enabling: %08x/%08x\n",
597 // activate APIC after activating by MSR was successful
598 // see "Intel Architecture Software Developer's Manual,
599 // Volume 3: System Programming Guide, Appendix E"
600 static FIASCO_INIT_AND_PM
602 Apic::route_pic_through_apic()
605 auto guard = lock_guard(cpu_lock);
607 // mask 8259 interrupts
608 Unsigned16 old_irqs = Pic::disable_all_save();
610 // set LINT0 to ExtINT, edge triggered
611 tmp_val = reg_read(APIC_lvt0);
612 tmp_val &= 0xfffe5800;
613 tmp_val |= 0x00000700;
614 reg_write(APIC_lvt0, tmp_val);
616 // set LINT1 to NMI, edge triggered
617 tmp_val = reg_read(APIC_lvt1);
618 tmp_val &= 0xfffe5800;
619 tmp_val |= 0x00000400;
620 reg_write(APIC_lvt1, tmp_val);
622 // unmask 8259 interrupts
623 Pic::restore_all(old_irqs);
625 printf("APIC was disabled --- routing PIC through APIC\n");
628 static FIASCO_INIT_CPU_AND_PM
632 auto guard = lock_guard(cpu_lock);
634 // mask timer interrupt and set vector to _not_ invalid value
635 reg_write(APIC_lvtt, reg_read(APIC_lvtt) | APIC_lvt_masked | 0xff);
638 // mask performance interrupt and set vector to a valid value
639 reg_write(APIC_lvtpc, reg_read(APIC_lvtpc) | APIC_lvt_masked | 0xff);
642 // mask thermal sensor interrupt and set vector to a valid value
643 reg_write(APIC_lvtthmr, reg_read(APIC_lvtthmr) | APIC_lvt_masked | 0xff);
646 // give us a hint if we have an APIC but it is disabled
649 Apic::test_present_but_disabled()
654 Unsigned64 msr = Cpu::rdmsr(APIC_base_msr);
655 return ((msr & 0xffffff000ULL) == 0xfee00000ULL);
658 // activate APIC by writing to appropriate MSR
659 static FIASCO_INIT_CPU_AND_PM
661 Apic::activate_by_msr()
665 msr = Cpu::rdmsr(APIC_base_msr);
666 phys_base = msr & 0xfffff000;
668 Cpu::wrmsr(msr, APIC_base_msr);
670 // now the CPU feature flags may have changed
671 cpu().update_features_info();
674 // check if we still receive interrupts after we changed the IRQ routing
675 PUBLIC static FIASCO_INIT_CPU
677 Apic::check_still_getting_interrupts()
682 Unsigned64 tsc_until;
683 Cpu_time clock_start = Kip::k()->clock;
685 tsc_until = Cpu::rdtsc();
686 tsc_until += 0x01000000; // > 10 Mio cycles should be sufficient until
687 // we have processors with more than 10 GHz
690 // kernel clock by timer interrupt updated?
691 if (Kip::k()->clock != clock_start)
694 } while (Cpu::rdtsc() < tsc_until);
712 reg_write(APIC_lvtpc, 0x400);
715 static FIASCO_INIT_CPU_AND_PM
717 Apic::calibrate_timer()
719 const unsigned calibrate_time = 50;
720 Unsigned32 count, tt1, tt2, result, dummy;
721 Unsigned32 runs = 0, frequency_ok;
728 timer_set_divisor(1);
729 timer_reg_write(1000000000);
732 auto guard = lock_guard(cpu_lock);
734 Pit::setup_channel2_to_20hz();
738 tt1 = timer_reg_read();
743 while ((Io::in8(0x61) & 0x20) == 0);
744 tt2 = timer_reg_read();
747 result = (tt1 - tt2) * timer_divisor;
754 :"=a" (frequency_khz), "=d" (dummy)
755 : "r" (calibrate_time), "a" (result), "d" (0));
757 frequency_ok = (frequency_khz < (1000<<11));
759 while (++runs < 10 && !frequency_ok);
762 panic("APIC frequency too high, adapt Apic::scaler_us_to_apic");
764 Kip::k()->frequency_bus = frequency_khz;
765 scaler_us_to_apic = Cpu::muldiv(1<<21, frequency_khz, 1000);
770 Apic::error_interrupt(Return_frame *regs)
772 Unsigned32 err1, err2;
774 // we are entering with disabled interrupts
775 err1 = Apic::get_num_errors();
776 Apic::clear_num_errors();
777 err2 = Apic::get_num_errors();
782 if (err1 == 0x80 || err2 == 0x80)
784 // ignore possible invalid access which may happen in
785 // jdb::do_dump_memory()
786 if (ignore_invalid_apic_reg_access)
789 printf("CPU%u: APIC invalid register access error at " L4_PTR_FMT "\n",
790 cxx::int_value<Cpu_number>(current_cpu()), regs->ip());
795 printf("CPU%u: APIC error %08x(%08x)\n",
796 cxx::int_value<Cpu_number>(current_cpu()), err1, err2);
799 // deactivate APIC by writing to appropriate MSR
809 val = reg_read(APIC_spiv);
811 reg_write(APIC_spiv, val);
813 val = Cpu::rdmsr(APIC_base_msr);
815 Cpu::wrmsr(val, APIC_base_msr);
818 PRIVATE static FIASCO_INIT_CPU_AND_PM
823 timer_set_divisor(1);
831 printf("Local APIC[%02x]: version=%02x max_lvt=%d\n",
832 get_id() >> 24, get_version(), get_max_lvt());
837 Apic::init(bool resume)
840 // FIXME: reset cached CPU features, we should add a special function
843 cpu().update_features_info();
845 was_present = present = test_present();
849 good_cpu = test_cpu();
851 if (good_cpu && Config::apic)
853 // activate; this could lead an disabled APIC to appear
854 // set base address of I/O registers to be able to access the registers
856 present = test_present();
863 // initialize if available
866 // map the Local APIC device registers
870 // set some interrupt vectors to appropriate values
873 // initialize APIC_spiv register
876 // initialize task-priority register
879 // test if local timer counts down
880 if ((present = check_working()))
883 // APIC _was_ not present before writing to msr so we have
884 // to set APIC_lvt0 and APIC_lvt1 to appropriate values
885 route_pic_through_apic();
890 panic("Local APIC not found");
894 apic_io_base = Mem_layout::Local_apic_page;