]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/apic-ia32.cpp
fiasco: Improved access to APIC through Jailhosue. Read and write instructions are...
[l4.git] / kernel / fiasco / src / kern / ia32 / apic-ia32.cpp
1 INTERFACE:
2
3 #include "per_cpu_data.h"
4 #include "types.h"
5 #include "initcalls.h"
6 #include "pm.h"
7
8 class Return_frame;
9 class Cpu;
10
11 class Apic : public Pm_object
12 {
13 public:
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; }
17
18   static Per_cpu<Static_object<Apic> > apic;
19
20 private:
21   Apic(const Apic&) = delete;
22   Apic &operator = (Apic const &) = delete;
23
24   Unsigned32 _id;
25   Unsigned32 _saved_apic_timer;
26
27   static void                   error_interrupt(Return_frame *regs)
28                                 asm ("apic_error_interrupt") FIASCO_FASTCALL;
29
30   static int                    present;
31   static int                    good_cpu;
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;
37
38   enum
39   {
40     APIC_id                     = 0x20,
41     APIC_lvr                    = 0x30,
42     APIC_tpr                    = 0x80,
43     APIC_tpri_mask              = 0xFF,
44     APIC_eoi                    = 0xB0,
45     APIC_ldr                    = 0xD0,
46     APIC_ldr_mask               = 0xFFul << 24,
47     APIC_dfr                    = 0xE0,
48     APIC_spiv                   = 0xF0,
49     APIC_isr                    = 0x100,
50     APIC_tmr                    = 0x180,
51     APIC_irr                    = 0x200,
52     APIC_esr                    = 0x280,
53     APIC_lvtt                   = 0x320,
54     APIC_lvtthmr                = 0x330,
55     APIC_lvtpc                  = 0x340,
56     APIC_lvt0                   = 0x350,
57     APIC_timer_base_div         = 0x2,
58     APIC_lvt1                   = 0x360,
59     APIC_lvterr                 = 0x370,
60     APIC_tmict                  = 0x380,
61     APIC_tmcct                  = 0x390,
62     APIC_tdcr                   = 0x3E0,
63
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,
70     APIC_tdr_div_1              = 0xB,
71     APIC_tdr_div_2              = 0x0,
72     APIC_tdr_div_4              = 0x1,
73     APIC_tdr_div_8              = 0x2,
74     APIC_tdr_div_16             = 0x3,
75     APIC_tdr_div_32             = 0x8,
76     APIC_tdr_div_64             = 0x9,
77     APIC_tdr_div_128            = 0xA,
78   };
79
80   enum
81   {
82     Mask                        =  1,
83     Trigger_mode                =  2,
84     Remote_irr                  =  4,
85     Pin_polarity                =  8,
86     Delivery_state              = 16,
87     Delivery_mode               = 32,
88   };
89
90   enum
91   {
92     APIC_base_msr               = 0x1b,
93   };
94 };
95
96 extern unsigned apic_spurious_interrupt_bug_cnt;
97 extern unsigned apic_spurious_interrupt_cnt;
98 extern unsigned apic_error_cnt;
99
100
101 //----------------------------------------------------------------------------
102 IMPLEMENTATION:
103 #include "cpu.h"
104
105 DEFINE_PER_CPU Per_cpu<Static_object<Apic> >  Apic::apic;
106
107 PUBLIC inline
108 Apic::Apic(Cpu_number cpu) : _id(get_id()) { register_pm(cpu); }
109
110
111 PRIVATE static
112 Cpu &
113 Apic::cpu() { return *Cpu::boot_cpu(); }
114
115 // FIXME: workaround for missing lambdas in gcc < 4.5
116 namespace {
117 struct By_id
118 {
119   Unsigned32 p;
120   By_id(Unsigned32 p) : p(p) {}
121   bool operator () (Apic const *a) const { return a && a->apic_id() == p; }
122 };
123 }
124
125 PUBLIC static
126 Cpu_number
127 Apic::find_cpu(Unsigned32 phys_id)
128 {
129   return apic.find_cpu(By_id(phys_id));
130 }
131
132 PUBLIC void
133 Apic::pm_on_suspend(Cpu_number)
134 {
135   _saved_apic_timer = timer_reg_read();
136 }
137
138 //----------------------------------------------------------------------------
139 IMPLEMENTATION [!mp]:
140
141 PUBLIC void
142 Apic::pm_on_resume(Cpu_number)
143 {
144   Apic::init(true);
145   timer_reg_write(_saved_apic_timer);
146 }
147
148 //----------------------------------------------------------------------------
149 IMPLEMENTATION [mp]:
150
151 PUBLIC void
152 Apic::pm_on_resume(Cpu_number cpu)
153 {
154   if (cpu == Cpu_number::boot_cpu())
155     Apic::init(true);
156   else
157     Apic::init_ap();
158   timer_reg_write(_saved_apic_timer);
159 }
160
161
162 //----------------------------------------------------------------------------
163 IMPLEMENTATION[ia32]:
164
165 PUBLIC static inline
166 Unsigned32
167 Apic::us_to_apic(Unsigned64 us)
168 {
169   Unsigned32 apic, dummy1, dummy2;
170   asm ("movl  %%edx, %%ecx              \n\t"
171        "mull  %4                        \n\t"
172        "movl  %%ecx, %%eax              \n\t"
173        "movl  %%edx, %%ecx              \n\t"
174        "mull  %4                        \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)
179        );
180   return apic;
181 }
182
183 IMPLEMENTATION[amd64]:
184
185 PUBLIC static inline
186 Unsigned32
187 Apic::us_to_apic(Unsigned64 us)
188 {
189   Unsigned32 apic, dummy;
190   asm ("mulq  %3                        \n\t"
191        "shrq  $21,%%rax                 \n\t"
192       :"=a"(apic), "=d"(dummy)
193       :"a"(us), "g"(scaler_us_to_apic)
194       );
195   return apic;
196 }
197
198 IMPLEMENTATION[ia32,amd64]:
199
200 #include <cassert>
201 #include <cstdio>
202 #include <cstdlib>
203 #include <cstring>
204
205 #include "config.h"
206 #include "cpu.h"
207 #include "cpu_lock.h"
208 #include "entry_frame.h"
209 #include "globals.h"
210 #include "io.h"
211 #include "kmem.h"
212 #include "kip.h"
213 #include "lock_guard.h"
214 #include "panic.h"
215 #include "processor.h"
216 #include "regdefs.h"
217 #include "pic.h"
218 #include "pit.h"
219
220 unsigned apic_spurious_interrupt_bug_cnt;
221 unsigned apic_spurious_interrupt_cnt;
222 unsigned apic_error_cnt;
223 Address  apic_io_base;
224
225 int        Apic::present;
226 int        Apic::good_cpu;
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;
232
233 int ignore_invalid_apic_reg_access;
234
235 PUBLIC static inline
236 Unsigned32
237 Apic::get_id()
238 {
239   return reg_read(APIC_id) & 0xff000000;
240 }
241
242 PRIVATE static inline
243 Unsigned32
244 Apic::get_version()
245 {
246   return reg_read(APIC_lvr) & 0xFF;
247 }
248
249 PRIVATE static inline NOEXPORT
250 int
251 Apic::is_integrated()
252 {
253   return reg_read(APIC_lvr) & 0xF0;
254 }
255
256 PRIVATE static inline NOEXPORT
257 Unsigned32
258 Apic::get_max_lvt_local()
259 {
260   return ((reg_read(APIC_lvr) >> 16) & 0xFF);
261 }
262
263 PRIVATE static inline NOEXPORT
264 Unsigned32
265 Apic::get_num_errors()
266 {
267   reg_write(APIC_esr, 0);
268   return reg_read(APIC_esr);
269 }
270
271 PRIVATE static inline NOEXPORT
272 void
273 Apic::clear_num_errors()
274 {
275   reg_write(APIC_esr, 0);
276   reg_write(APIC_esr, 0);
277 }
278
279 PUBLIC static inline
280 unsigned
281 Apic::get_frequency_khz()
282 {
283   return frequency_khz;
284 }
285
286 PUBLIC static inline
287 Unsigned32
288 Apic::reg_read(unsigned reg)
289 {
290   Unsigned32 val;
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));
294   return val;
295 }
296
297 PUBLIC static inline
298 void
299 Apic::reg_write(unsigned reg, Unsigned32 val)
300 {
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));
304 }
305
306 PUBLIC static inline
307 int
308 Apic::reg_delivery_mode(Unsigned32 val)
309 {
310   return (val >> 8) & 7;
311 }
312
313 PUBLIC static inline
314 int
315 Apic::reg_lvt_vector(Unsigned32 val)
316 {
317   return val & 0xff;
318 }
319
320 PUBLIC static inline
321 Unsigned32
322 Apic::timer_reg_read()
323 {
324   return reg_read(APIC_tmcct);
325 }
326
327 PUBLIC static inline
328 Unsigned32
329 Apic::timer_reg_read_initial()
330 {
331   return reg_read(APIC_tmict);
332 }
333
334 PUBLIC static inline
335 void
336 Apic::timer_reg_write(Unsigned32 val)
337 {
338   reg_read(APIC_tmict);
339   reg_write(APIC_tmict, val);
340 }
341
342 PUBLIC static inline NEEDS["cpu.h"]
343 Address
344 Apic::apic_page_phys()
345 { return Cpu::rdmsr(APIC_base_msr) & 0xfffff000; }
346
347 // set the global pagetable entry for the Local APIC device registers
348 PUBLIC
349 static FIASCO_INIT_AND_PM
350 void
351 Apic::map_apic_page()
352 {
353   Address offs;
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,
359                       false, true, &offs);
360
361   Kip::k()->add_mem_region(Mem_desc(base, base + Config::PAGE_SIZE - 1, Mem_desc::Reserved));
362
363   assert(offs == 0);
364 }
365
366 // check CPU type if APIC could be present
367 static FIASCO_INIT_AND_PM
368 int
369 Apic::test_cpu()
370 {
371   if (!cpu().can_wrmsr() || !(cpu().features() & FEAT_TSC))
372     return 0;
373
374   if (cpu().vendor() == Cpu::Vendor_intel)
375     {
376       if (cpu().family() == 15)
377         return 1;
378       if (cpu().family() >= 6)
379         return 1;
380     }
381   if (cpu().vendor() == Cpu::Vendor_amd && cpu().family() >= 6)
382     return 1;
383
384   return 0;
385 }
386
387 // test if APIC present
388 static inline
389 int
390 Apic::test_present()
391 {
392   return cpu().features() & FEAT_APIC;
393 }
394
395 PUBLIC static inline
396 void
397 Apic::timer_enable_irq()
398 {
399   Unsigned32 tmp_val;
400
401   tmp_val = reg_read(APIC_lvtt);
402   tmp_val &= ~(APIC_lvt_masked);
403   reg_write(APIC_lvtt, tmp_val);
404 }
405
406 PUBLIC static inline
407 void
408 Apic::timer_disable_irq()
409 {
410   Unsigned32 tmp_val;
411
412   tmp_val = reg_read(APIC_lvtt);
413   tmp_val |= APIC_lvt_masked;
414   reg_write(APIC_lvtt, tmp_val);
415 }
416
417 PUBLIC static inline
418 int
419 Apic::timer_is_irq_enabled()
420 {
421   return ~reg_read(APIC_lvtt) & APIC_lvt_masked;
422 }
423
424 PUBLIC static inline
425 void
426 Apic::timer_set_periodic()
427 {
428   Unsigned32 tmp_val = reg_read(APIC_lvtt);
429   tmp_val |= APIC_lvt_timer_periodic;
430   reg_write(APIC_lvtt, tmp_val);
431 }
432
433 PUBLIC static inline
434 void
435 Apic::timer_set_one_shot()
436 {
437   Unsigned32 tmp_val = reg_read(APIC_lvtt);
438   tmp_val &= ~APIC_lvt_timer_periodic;
439   reg_write(APIC_lvtt, tmp_val);
440 }
441
442 PUBLIC static inline
443 void
444 Apic::timer_assign_irq_vector(unsigned vector)
445 {
446   Unsigned32 tmp_val = reg_read(APIC_lvtt);
447   tmp_val &= 0xffffff00;
448   tmp_val |= vector;
449   reg_write(APIC_lvtt, tmp_val);
450 }
451
452 PUBLIC static inline
453 void
454 Apic::irq_ack()
455 {
456   reg_read(APIC_spiv);
457   reg_write(APIC_eoi, 0);
458 }
459
460 static
461 void
462 Apic::timer_set_divisor(unsigned newdiv)
463 {
464   int i;
465   int div = -1;
466   int divval = newdiv;
467   Unsigned32 tmp_value;
468
469   static int divisor_tab[8] =
470     {
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
473     };
474
475   for (i=0; i<8; i++)
476     {
477       if (divval & 1)
478         {
479           if (divval & ~1)
480             {
481               printf("bad APIC divisor %u\n", newdiv);
482               return;
483             }
484           div = divisor_tab[i];
485           break;
486         }
487       divval >>= 1;
488     }
489
490   if (div != -1)
491     {
492       timer_divisor = newdiv;
493       tmp_value = reg_read(APIC_tdcr);
494       tmp_value &= ~0x1F;
495       tmp_value |= div;
496       reg_write(APIC_tdcr, tmp_value);
497     }
498 }
499
500 static
501 int
502 Apic::get_max_lvt()
503 {
504   return is_integrated() ? get_max_lvt_local() : 2;
505 }
506
507 PUBLIC static inline
508 int
509 Apic::have_pcint()
510 {
511   return (present && (get_max_lvt() >= 4));
512 }
513
514 PUBLIC static inline
515 int
516 Apic::have_tsint()
517 {
518   return (present && (get_max_lvt() >= 5));
519 }
520
521 // check if APIC is working (check timer functionality)
522 static FIASCO_INIT_AND_PM
523 int
524 Apic::check_working()
525 {
526   Unsigned64 tsc_until;
527
528   timer_disable_irq();
529   timer_set_divisor(1);
530   timer_reg_write(0x10000000);
531
532   tsc_until = Cpu::rdtsc() + 0x400;  // we only have to wait for one bus cycle
533
534   do
535     {
536       if (timer_reg_read() != 0x10000000)
537         return 1;
538     } while (Cpu::rdtsc() < tsc_until);
539
540   return 0;
541 }
542
543 static FIASCO_INIT_CPU_AND_PM
544 void
545 Apic::init_spiv()
546 {
547   Unsigned32 tmp_val;
548
549   tmp_val = reg_read(APIC_spiv);
550   tmp_val |= (1<<8);            // enable APIC
551   tmp_val &= ~(1<<9);           // enable Focus Processor Checking
552   tmp_val &= ~0xff;
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);
556 }
557
558 PUBLIC static inline NEEDS[Apic::reg_write]
559 void
560 Apic::tpr(unsigned prio)
561 { reg_write(APIC_tpr, prio); }
562
563 PUBLIC static inline NEEDS[Apic::reg_read]
564 unsigned
565 Apic::tpr()
566 { return reg_read(APIC_tpr); }
567
568 static FIASCO_INIT_CPU_AND_PM
569 void
570 Apic::init_tpr()
571 {
572   reg_write(APIC_tpr, 0);
573 }
574
575 // activate APIC error interrupt
576 static FIASCO_INIT_CPU_AND_PM
577 void
578 Apic::enable_errors()
579 {
580   if (is_integrated())
581     {
582       Unsigned32 tmp_val, before, after;
583
584       if (get_max_lvt() > 3)
585         clear_num_errors();
586       before = get_num_errors();
587
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);
592
593       if (get_max_lvt() > 3)
594         clear_num_errors();
595       after = get_num_errors();
596       printf("APIC ESR value before/after enabling: %08x/%08x\n",
597             before, after);
598     }
599 }
600
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
605 void
606 Apic::route_pic_through_apic()
607 {
608   Unsigned32 tmp_val;
609   auto guard = lock_guard(cpu_lock);
610
611   // mask 8259 interrupts
612   Unsigned16 old_irqs = Pic::disable_all_save();
613
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);
619
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);
625
626   // unmask 8259 interrupts
627   Pic::restore_all(old_irqs);
628
629   printf("APIC was disabled --- routing PIC through APIC\n");
630 }
631
632 static FIASCO_INIT_CPU_AND_PM
633 void
634 Apic::init_lvt()
635 {
636   auto guard = lock_guard(cpu_lock);
637
638   // mask timer interrupt and set vector to _not_ invalid value
639   reg_write(APIC_lvtt, reg_read(APIC_lvtt) | APIC_lvt_masked | 0xff);
640
641   if (have_pcint())
642     // mask performance interrupt and set vector to a valid value
643     reg_write(APIC_lvtpc, reg_read(APIC_lvtpc) | APIC_lvt_masked | 0xff);
644
645   if (have_tsint())
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);
648 }
649
650 // give us a hint if we have an APIC but it is disabled
651 PUBLIC static
652 int
653 Apic::test_present_but_disabled()
654 {
655   if (!good_cpu)
656     return 0;
657
658   Unsigned64 msr = Cpu::rdmsr(APIC_base_msr);
659   return ((msr & 0xffffff000ULL) == 0xfee00000ULL);
660 }
661
662 // activate APIC by writing to appropriate MSR
663 static FIASCO_INIT_CPU_AND_PM
664 void
665 Apic::activate_by_msr()
666 {
667   Unsigned64 msr;
668
669   msr = Cpu::rdmsr(APIC_base_msr);
670   phys_base = msr & 0xfffff000;
671   msr |= (1<<11);
672   Cpu::wrmsr(msr, APIC_base_msr);
673
674   // now the CPU feature flags may have changed
675   cpu().update_features_info();
676 }
677
678 // check if we still receive interrupts after we changed the IRQ routing
679 PUBLIC static FIASCO_INIT_CPU
680 int
681 Apic::check_still_getting_interrupts()
682 {
683   if (!Config::apic)
684     return 0;
685
686   Unsigned64 tsc_until;
687   Cpu_time clock_start = Kip::k()->clock;
688
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
692   do
693     {
694       // kernel clock by timer interrupt updated?
695       if (Kip::k()->clock != clock_start)
696         // yes, succesful
697         return 1;
698     } while (Cpu::rdtsc() < tsc_until);
699
700   // timeout
701   return 0;
702 }
703
704 PUBLIC static
705 inline int
706 Apic::is_present()
707 {
708   return present;
709 }
710
711 PUBLIC static
712 void
713 Apic::set_perf_nmi()
714 {
715   if (have_pcint())
716     reg_write(APIC_lvtpc, 0x400);
717 }
718
719 static FIASCO_INIT_CPU_AND_PM
720 void
721 Apic::calibrate_timer()
722 {
723   const unsigned calibrate_time = 50;
724   Unsigned32 count, tt1, tt2, result, dummy;
725   Unsigned32 runs = 0, frequency_ok;
726
727   do
728     {
729       frequency_khz = 0;
730
731       timer_disable_irq();
732       timer_set_divisor(1);
733       timer_reg_write(1000000000);
734
735         {
736           auto guard = lock_guard(cpu_lock);
737
738           Pit::setup_channel2_to_20hz();
739
740           count = 0;
741
742           tt1 = timer_reg_read();
743           do
744             {
745               count++;
746             }
747           while ((Io::in8(0x61) & 0x20) == 0);
748           tt2 = timer_reg_read();
749         }
750
751       result = (tt1 - tt2) * timer_divisor;
752
753       // APIC not running
754       if (count <= 1)
755         return;
756
757       asm ("divl %2"
758           :"=a" (frequency_khz), "=d" (dummy)
759           : "r" (calibrate_time), "a" (result), "d" (0));
760
761       frequency_ok = (frequency_khz < (1000<<11));
762     }
763   while (++runs < 10 && !frequency_ok);
764
765   if (!frequency_ok)
766     panic("APIC frequency too high, adapt Apic::scaler_us_to_apic");
767
768   Kip::k()->frequency_bus = frequency_khz;
769   scaler_us_to_apic       = Cpu::muldiv(1<<21, frequency_khz, 1000);
770 }
771
772 IMPLEMENT
773 void
774 Apic::error_interrupt(Return_frame *regs)
775 {
776   Unsigned32 err1, err2;
777
778   // we are entering with disabled interrupts
779   err1 = Apic::get_num_errors();
780   Apic::clear_num_errors();
781   err2 = Apic::get_num_errors();
782   Apic::irq_ack();
783
784   cpu_lock.clear();
785
786   if (err1 == 0x80 || err2 == 0x80)
787     {
788       // ignore possible invalid access which may happen in
789       // jdb::do_dump_memory()
790       if (ignore_invalid_apic_reg_access)
791         return;
792
793       printf("CPU%u: APIC invalid register access error at " L4_PTR_FMT "\n",
794              cxx::int_value<Cpu_number>(current_cpu()), regs->ip());
795       return;
796     }
797
798   apic_error_cnt++;
799   printf("CPU%u: APIC error %08x(%08x)\n",
800          cxx::int_value<Cpu_number>(current_cpu()), err1, err2);
801 }
802
803 // deactivate APIC by writing to appropriate MSR
804 PUBLIC static
805 void
806 Apic::done()
807 {
808   Unsigned64 val;
809
810   if (!present)
811     return;
812
813   val = reg_read(APIC_spiv);
814   val &= ~(1<<8);
815   reg_write(APIC_spiv, val);
816
817   val = Cpu::rdmsr(APIC_base_msr);
818   val  &= ~(1<<11);
819   Cpu::wrmsr(val, APIC_base_msr);
820 }
821
822 PRIVATE static FIASCO_INIT_CPU_AND_PM
823 void
824 Apic::init_timer()
825 {
826   calibrate_timer();
827   timer_set_divisor(1);
828   enable_errors();
829 }
830
831 PUBLIC static
832 void
833 Apic::dump_info()
834 {
835   printf("Local APIC[%02x]: version=%02x max_lvt=%d\n",
836          get_id() >> 24, get_version(), get_max_lvt());
837 }
838
839 IMPLEMENT
840 void
841 Apic::init(bool resume)
842 {
843   int was_present;
844   // FIXME: reset cached CPU features, we should add a special function
845   // for the apic bit
846   if(resume)
847     cpu().update_features_info();
848
849   was_present = present = test_present();
850
851   if (!was_present)
852     {
853       good_cpu = test_cpu();
854
855       if (good_cpu && Config::apic)
856         {
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
859           activate_by_msr();
860           present = test_present();
861         }
862     }
863
864   if (!Config::apic)
865     return;
866
867   // initialize if available
868   if (present)
869     {
870       // map the Local APIC device registers
871       if (!resume)
872         map_apic_page();
873
874       // set some interrupt vectors to appropriate values
875       init_lvt();
876
877       // initialize APIC_spiv register
878       init_spiv();
879
880       // initialize task-priority register
881       init_tpr();
882
883       // test if local timer counts down
884       if ((present = check_working()))
885         {
886           if (!was_present)
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();
890         }
891     }
892
893   if (!present)
894     panic("Local APIC not found");
895
896   dump_info();
897
898   apic_io_base = Mem_layout::Local_apic_page;
899   init_timer();
900 }