]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/arm/cpu-arm.cpp
dddedde63dcb3a5247778ffb686e7e81d1ba0122
[l4.git] / kernel / fiasco / src / kern / arm / cpu-arm.cpp
1 INTERFACE [arm]:
2
3 #include "io.h"
4 #include "mem_layout.h"
5 #include "mem_unit.h"
6 #include "types.h"
7 #include "per_cpu_data.h"
8 #include "processor.h"
9
10 EXTENSION
11 class Cpu
12 {
13 public:
14   void init(bool is_boot_cpu = false);
15
16   static void early_init();
17
18   static Per_cpu<Cpu> cpus;
19   static Cpu *boot_cpu() { return _boot_cpu; }
20
21   enum {
22     Cp15_c1_mmu             = 1 << 0,
23     Cp15_c1_alignment_check = 1 << 1,
24     Cp15_c1_cache           = 1 << 2,
25     Cp15_c1_branch_predict  = 1 << 11,
26     Cp15_c1_insn_cache      = 1 << 12,
27     Cp15_c1_high_vector     = 1 << 13,
28   };
29
30   Cpu(unsigned id) { set_id(id); }
31
32
33   struct Ids {
34     Mword _pfr[2], _dfr0, _afr0, _mmfr[4];
35   };
36   void id_init();
37
38   enum {
39     Copro_dbg_model_not_supported = 0,
40     Copro_dbg_model_v6            = 2,
41     Copro_dbg_model_v6_1          = 3,
42     Copro_dbg_model_v7            = 4,
43   };
44
45   unsigned copro_dbg_model() const { return _cpu_id._dfr0 & 0xf; }
46
47 private:
48   static Cpu *_boot_cpu;
49
50   unsigned _phys_id;
51   Ids _cpu_id;
52 };
53
54 // ------------------------------------------------------------------------
55 INTERFACE [arm && armv5]:
56
57 EXTENSION class Cpu
58 {
59 public:
60   enum {
61     Cp15_c1_write_buffer    = 1 << 3,
62     Cp15_c1_prog32          = 1 << 4,
63     Cp15_c1_data32          = 1 << 5,
64     Cp15_c1_late_abort      = 1 << 6,
65     Cp15_c1_big_endian      = 1 << 7,
66     Cp15_c1_system_protect  = 1 << 8,
67     Cp15_c1_rom_protect     = 1 << 9,
68     Cp15_c1_f               = 1 << 10,
69     Cp15_c1_rr              = 1 << 14,
70     Cp15_c1_l4              = 1 << 15,
71
72     Cp15_c1_generic         = Cp15_c1_mmu
73                               | (Config::Cp15_c1_use_alignment_check ?  Cp15_c1_alignment_check : 0)
74                               | Cp15_c1_write_buffer
75                               | Cp15_c1_prog32
76                               | Cp15_c1_data32
77                               | Cp15_c1_late_abort
78                               | Cp15_c1_rom_protect
79                               | Cp15_c1_high_vector,
80
81     Cp15_c1_cache_bits      = Cp15_c1_cache
82                               | Cp15_c1_insn_cache
83                               | Cp15_c1_write_buffer,
84
85   };
86 };
87
88 INTERFACE [arm && armv6]:
89
90 EXTENSION class Cpu
91 {
92 public:
93   enum {
94     Cp15_c1_l4              = 1 << 15,
95     Cp15_c1_u               = 1 << 22,
96     Cp15_c1_xp              = 1 << 23,
97     Cp15_c1_ee              = 1 << 25,
98     Cp15_c1_nmfi            = 1 << 27,
99     Cp15_c1_tex             = 1 << 28,
100     Cp15_c1_force_ap        = 1 << 29,
101
102     Cp15_c1_generic         = Cp15_c1_mmu
103                               | (Config::Cp15_c1_use_alignment_check ?  Cp15_c1_alignment_check : 0)
104                               | Cp15_c1_branch_predict
105                               | Cp15_c1_high_vector
106                               | Cp15_c1_u
107                               | Cp15_c1_xp,
108
109     Cp15_c1_cache_bits      = Cp15_c1_cache
110                               | Cp15_c1_insn_cache,
111   };
112 };
113
114 INTERFACE [arm && armv7 && armca8]:
115
116 EXTENSION class Cpu
117 {
118 public:
119   enum {
120     Cp15_c1_ee              = 1 << 25,
121     Cp15_c1_nmfi            = 1 << 27,
122     Cp15_c1_te              = 1 << 30,
123     Cp15_c1_rao_sbop        = (0xf << 3) | (1 << 16) | (1 << 18) | (1 << 22) | (1 << 23),
124
125     Cp15_c1_cache_bits      = Cp15_c1_cache
126                               | Cp15_c1_insn_cache,
127
128     Cp15_c1_generic         = Cp15_c1_mmu
129                               | (Config::Cp15_c1_use_alignment_check ?  Cp15_c1_alignment_check : 0)
130                               | Cp15_c1_branch_predict
131                               | Cp15_c1_rao_sbop
132                               | Cp15_c1_high_vector,
133   };
134 };
135
136 INTERFACE [arm && armv7 && armca9]:
137
138 EXTENSION class Cpu
139 {
140 public:
141   enum {
142     Cp15_c1_sw              = 1 << 10,
143     Cp15_c1_ha              = 1 << 17,
144     Cp15_c1_ee              = 1 << 25,
145     Cp15_c1_nmfi            = 1 << 27,
146     Cp15_c1_te              = 1 << 30,
147     Cp15_c1_rao_sbop        = (0xf << 3) | (1 << 16) | (1 << 18) | (1 << 22) | (1 << 23),
148
149     Cp15_c1_cache_bits      = Cp15_c1_cache
150                               | Cp15_c1_insn_cache,
151
152     Cp15_c1_generic         = Cp15_c1_mmu
153                               | (Config::Cp15_c1_use_alignment_check ?  Cp15_c1_alignment_check : 0)
154                               | Cp15_c1_branch_predict
155                               | Cp15_c1_high_vector
156                               | Cp15_c1_rao_sbop
157                               | (Config::Cp15_c1_use_a9_swp_enable ?  Cp15_c1_sw : 0),
158   };
159 };
160
161 INTERFACE [arm && (mpcore || armca9)]:
162
163 class Scu
164 {
165 public:
166   enum
167   {
168     Control      = Mem_layout::Mp_scu_map_base + 0x0,
169     Config       = Mem_layout::Mp_scu_map_base + 0x4,
170     Power_status = Mem_layout::Mp_scu_map_base + 0x8,
171     Inv          = Mem_layout::Mp_scu_map_base + 0xc,
172
173     Control_ic_standby     = 1 << 6,
174     Control_scu_standby    = 1 << 5,
175     Control_force_port0    = 1 << 4,
176     Control_spec_linefill  = 1 << 3,
177     Control_ram_parity     = 1 << 2,
178     Control_addr_filtering = 1 << 1,
179     Control_enable         = 1 << 0,
180   };
181
182   static void reset() { Io::write<Mword>(0xffffffff, Inv); }
183
184   static void enable(Mword bits = 0)
185   {
186     Unsigned32 ctrl = Io::read<Unsigned32>(Control);
187     if (!(ctrl & Control_enable))
188       Io::write<Unsigned32>(ctrl | bits | Control_enable, Control);
189   }
190 };
191
192
193 INTERFACE [arm]:
194
195 EXTENSION class Cpu
196 {
197 public:
198   enum {
199     Cp15_c1_cache_enabled  = Cp15_c1_generic | Cp15_c1_cache_bits,
200     Cp15_c1_cache_disabled = Cp15_c1_generic,
201   };
202 };
203
204 //---------------------------------------------------------------------------
205 INTERFACE [arm && !bsp_cpu]:
206
207 EXTENSION class Cpu
208 {
209 private:
210   void bsp_init(bool) {}
211 };
212
213 //---------------------------------------------------------------------------
214 INTERFACE [arm && (mpcore || armca9) && !bsp_cpu]:
215
216 EXTENSION class Scu
217 {
218 public:
219   enum { Bsp_enable_bits = 0 };
220 };
221
222 //-------------------------------------------------------------------------
223 IMPLEMENTATION [arm]:
224
225 PRIVATE static inline
226 Mword
227 Cpu::midr()
228 {
229   Mword m;
230   asm volatile ("mrc p15, 0, %0, c0, c0, 0" : "=r" (m));
231   return m;
232 }
233
234 IMPLEMENTATION [arm && armv6]: // -----------------------------------------
235
236 PUBLIC static inline NEEDS[Cpu::set_actrl]
237 void
238 Cpu::enable_smp()
239 {
240   set_actrl(0x20);
241 }
242
243 PUBLIC static inline NEEDS[Cpu::clear_actrl]
244 void
245 Cpu::disable_smp()
246 {
247   clear_actrl(0x20);
248 }
249
250 IMPLEMENTATION [arm && armv7]: //------------------------------------------
251
252 PUBLIC static inline NEEDS[Cpu::midr]
253 bool
254 Cpu::is_smp_capable()
255 {
256   // ACTRL is implementation defined
257   return (midr() & 0xff0ffff0) == 0x410fc090;
258 }
259
260 PUBLIC static inline
261 void
262 Cpu::enable_smp()
263 {
264   if (!is_smp_capable())
265     return;
266
267   Mword actrl;
268   asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (actrl));
269   if (!(actrl & 0x40))
270     asm volatile ("mcr p15, 0, %0, c1, c0, 1" : : "r" (actrl | 0x41));
271 }
272
273 PUBLIC static inline NEEDS[Cpu::clear_actrl]
274 void
275 Cpu::disable_smp()
276 {
277   if (!is_smp_capable())
278     return;
279
280   clear_actrl(0x41);
281 }
282
283 //---------------------------------------------------------------------------
284 IMPLEMENTATION [arm && (mpcore || armca9)]:
285
286 PRIVATE static inline void
287 Cpu::early_init_platform()
288 {
289   Scu::reset();
290   Scu::enable(Scu::Bsp_enable_bits);
291
292   Io::write<Mword>(Io::read<Mword>(Mem_layout::Gic_cpu_map_base + 0) | 1,
293                    Mem_layout::Gic_cpu_map_base + 0);
294   Io::write<Mword>(Io::read<Mword>(Mem_layout::Gic_dist_map_base + 0) | 1,
295                    Mem_layout::Gic_dist_map_base + 0);
296
297   Mem_unit::clean_dcache();
298
299   enable_smp();
300 }
301
302 //---------------------------------------------------------------------------
303 IMPLEMENTATION [arm && !(mpcore || armca9)]:
304
305 PRIVATE static inline void Cpu::early_init_platform()
306 {}
307
308 //---------------------------------------------------------------------------
309 IMPLEMENTATION [arm]:
310
311 #include <cstdio>
312 #include <cstring>
313 #include <panic.h>
314
315 #include "io.h"
316 #include "pagetable.h"
317 #include "kmem_space.h"
318 #include "kmem_alloc.h"
319 #include "mem_unit.h"
320 #include "processor.h"
321 #include "ram_quota.h"
322
323 DEFINE_PER_CPU_P(0) Per_cpu<Cpu> Cpu::cpus(true);
324 Cpu *Cpu::_boot_cpu;
325
326 PUBLIC static inline
327 Mword
328 Cpu::stack_align(Mword stack)
329 { return stack & ~0x3; }
330
331
332 IMPLEMENT
333 void Cpu::early_init()
334 {
335   // switch to supervisor mode and intialize the memory system
336   asm volatile ( " mov  r2, r13             \n"
337                  " mov  r3, r14             \n"
338                  " msr  cpsr_c, %1          \n"
339                  " mov  r13, r2             \n"
340                  " mov  r14, r3             \n"
341
342                  " mcr  p15, 0, %0, c1, c0  \n"
343                  :
344                  : "r" (Config::Cache_enabled
345                         ? Cp15_c1_cache_enabled : Cp15_c1_cache_disabled),
346                    "I" (0x0d3)
347                  : "r2", "r3");
348
349   early_init_platform();
350
351   Mem_unit::flush_cache();
352 }
353
354
355 PUBLIC static inline
356 bool
357 Cpu::have_superpages()
358 { return true; }
359
360 PUBLIC static inline
361 void
362 Cpu::debugctl_enable()
363 {}
364
365 PUBLIC static inline
366 void
367 Cpu::debugctl_disable()
368 {}
369
370 PUBLIC static inline NEEDS["types.h"]
371 Unsigned32
372 Cpu::get_scaler_tsc_to_ns()
373 { return 0; }
374
375 PUBLIC static inline NEEDS["types.h"]
376 Unsigned32
377 Cpu::get_scaler_tsc_to_us()
378 { return 0; }
379
380 PUBLIC static inline NEEDS["types.h"]
381 Unsigned32
382 Cpu::get_scaler_ns_to_tsc()
383 { return 0; }
384
385 PUBLIC static inline
386 bool
387 Cpu::tsc()
388 { return 0; }
389
390 PUBLIC static inline
391 Unsigned64
392 Cpu::rdtsc (void)
393 { return 0; }
394
395 PUBLIC static
396 void Cpu::init_mmu()
397 {
398   extern char ivt_start;
399   // map the interrupt vector table to 0xffff0000
400   Pte pte = Kmem_space::kdir()->walk((void*)Kmem_space::Ivt_base, 4096, true,
401                                      Kmem_alloc::q_allocator(Ram_quota::root),
402                                      Kmem_space::kdir());
403
404   pte.set((unsigned long)&ivt_start, 4096,
405           Mem_page_attr(Page::KERN_RW | Page::CACHEABLE), true);
406
407   Mem_unit::tlb_flush();
408 }
409
410 PUBLIC inline
411 unsigned
412 Cpu::phys_id() const
413 { return _phys_id; }
414
415 IMPLEMENT
416 void
417 Cpu::init(bool is_boot_cpu)
418 {
419   if (is_boot_cpu)
420     {
421       _boot_cpu = this;
422       set_online(1);
423     }
424
425   _phys_id = Proc::cpu_id();
426
427   init_tz();
428   id_init();
429   init_errata_workarounds();
430   bsp_init(is_boot_cpu);
431
432   print_infos();
433 }
434
435 PUBLIC static inline
436 void
437 Cpu::enable_dcache()
438 {
439   asm volatile("mrc     p15, 0, %0, c1, c0, 0 \n"
440                "orr     %0, %1                \n"
441                "mcr     p15, 0, %0, c1, c0, 0 \n"
442                : : "r" (0), "i" (Cp15_c1_cache));
443 }
444
445 PUBLIC static inline
446 void
447 Cpu::disable_dcache()
448 {
449   asm volatile("mrc     p15, 0, %0, c1, c0, 0 \n"
450                "bic     %0, %1                \n"
451                "mcr     p15, 0, %0, c1, c0, 0 \n"
452                : : "r" (0), "i" (Cp15_c1_cache));
453 }
454
455 //---------------------------------------------------------------------------
456 IMPLEMENTATION [arm && !armv6plus]:
457
458 IMPLEMENT
459 void
460 Cpu::id_init()
461 {
462 }
463
464 //---------------------------------------------------------------------------
465 IMPLEMENTATION [arm && armv6plus]:
466
467 PRIVATE static inline
468 void
469 Cpu::set_actrl(Mword bit_mask)
470 {
471   Mword t;
472   asm volatile("mrc p15, 0, %0, c1, c0, 1 \n\t"
473                "orr %0, %0, %1            \n\t"
474                "mcr p15, 0, %0, c1, c0, 1 \n\t"
475                : "=r"(t) : "r" (bit_mask));
476 }
477
478 PRIVATE static inline
479 void
480 Cpu::clear_actrl(Mword bit_mask)
481 {
482   Mword t;
483   asm volatile("mrc p15, 0, %0, c1, c0, 1 \n\t"
484                "bic %0, %1                \n\t"
485                "mcr p15, 0, %0, c1, c0, 1 \n\t"
486                : "=r"(t) : "r" (bit_mask));
487 }
488
489 IMPLEMENT
490 void
491 Cpu::id_init()
492 {
493   __asm__("mrc p15, 0, %0, c0, c1, 0": "=r" (_cpu_id._pfr[0]));
494   __asm__("mrc p15, 0, %0, c0, c1, 1": "=r" (_cpu_id._pfr[1]));
495   __asm__("mrc p15, 0, %0, c0, c1, 2": "=r" (_cpu_id._dfr0));
496   __asm__("mrc p15, 0, %0, c0, c1, 3": "=r" (_cpu_id._afr0));
497   __asm__("mrc p15, 0, %0, c0, c1, 4": "=r" (_cpu_id._mmfr[0]));
498   __asm__("mrc p15, 0, %0, c0, c1, 5": "=r" (_cpu_id._mmfr[1]));
499   __asm__("mrc p15, 0, %0, c0, c1, 6": "=r" (_cpu_id._mmfr[2]));
500   __asm__("mrc p15, 0, %0, c0, c1, 7": "=r" (_cpu_id._mmfr[3]));
501 }
502
503 //---------------------------------------------------------------------------
504 IMPLEMENTATION [!arm_cpu_errata || !armv6plus]:
505
506 PRIVATE static inline
507 void Cpu::init_errata_workarounds() {}
508
509 //---------------------------------------------------------------------------
510 IMPLEMENTATION [arm_cpu_errata && armv6plus]:
511
512 PRIVATE static inline
513 void
514 Cpu::set_c15_c0_1(Mword bits_mask)
515 {
516   Mword t;
517   asm volatile("mrc p15, 0, %0, c15, c0, 1 \n\t"
518                "orr %0, %0, %1             \n\t"
519                "mcr p15, 0, %0, c15, c0, 1 \n\t"
520                : "=r"(t) : "r" (bits_mask));
521 }
522
523 PRIVATE static inline NEEDS[Cpu::midr]
524 void
525 Cpu::init_errata_workarounds()
526 {
527   Mword mid = midr();
528
529   if ((mid & 0xff000000) == 0x41000000) // ARM CPU
530     {
531       Mword rev = ((mid & 0x00f00000) >> 16) | (mid & 0x0f);
532       Mword part = (mid & 0x0000fff0) >> 4;
533
534       if (part == 0xc08) // Cortex A8
535         {
536           // errata: 430973
537           if ((rev & 0xf0) == 0x10)
538             set_actrl(1 << 6); // IBE to 1
539
540           // errata: 458693
541           if (rev == 0x20)
542             set_actrl((1 << 5) | (1 << 9)); // L1NEON & PLDNOP
543
544           // errata: 460075
545           if (rev == 0x20)
546             {
547               Mword t;
548               asm volatile ("mrc p15, 1, %0, c9, c0, 2 \n\t"
549                             "orr %0, %0, #1 << 22      \n\t" // Write alloc disable
550                             "mcr p15, 1, %0, c9, c0, 2 \n\t" : "=r"(t));
551             }
552         }
553
554       if (part == 0xc09) // Cortex A9
555         {
556           // errata: 742230 (DMB errata)
557           // make DMB a DSB to fix behavior
558           if (rev <= 0x22) // <= r2p2
559             set_c15_c0_1(1 << 4);
560
561           // errata: 742231
562           if (rev == 0x20 || rev == 0x21 || rev == 0x22)
563             set_c15_c0_1((1 << 12) | (1 << 22));
564
565           // errata: 743622
566           if ((rev & 0xf0) == 0x20)
567             set_c15_c0_1(1 << 6);
568
569           // errata: 751472
570           if (rev < 0x30)
571             set_c15_c0_1(1 << 11);
572         }
573     }
574 }
575
576 //---------------------------------------------------------------------------
577 IMPLEMENTATION [arm && !tz]:
578
579 PRIVATE static inline
580 void
581 Cpu::init_tz()
582 {}
583
584 //---------------------------------------------------------------------------
585 INTERFACE [arm && tz]:
586
587 EXTENSION class Cpu
588 {
589 public:
590
591   static char monitor_vector_base asm ("monitor_vector_base");
592 };
593
594 //---------------------------------------------------------------------------
595 IMPLEMENTATION [arm && tz]:
596
597 #include <cassert>
598
599 PRIVATE inline NEEDS[<cassert>]
600 void
601 Cpu::init_tz()
602 {
603   // set monitor vector base address
604   assert(!((Mword)&monitor_vector_base & 31));
605   tz_mvbar((Mword)&monitor_vector_base);
606
607   // enable nonsecure access to vfp coprocessor
608   asm volatile("mov r0, #0xc00;"
609                "mcr p15, 0, r0, c1, c1, 2;"
610                : : : "r0"
611               );
612
613   enable_irq_ovrr();
614 }
615
616 PUBLIC inline
617 void
618 Cpu::tz_switch_to_ns(Mword *nonsecure_state)
619 {
620   volatile register Mword r0 asm("r0") = (Mword)nonsecure_state;
621   extern char go_nonsecure;
622
623   asm volatile("stmdb sp!, {fp}   \n"
624                "stmdb sp!, {r0}   \n"
625                "mov    r2, sp     \n" // copy sp_svc to sp_mon
626                "cps    #0x16      \n" // switch to monitor mode
627                "mov    sp, r2     \n"
628                "adr    r3, 1f     \n" // save return eip
629                "mrs    r4, cpsr   \n" // save return psr
630                "mov    pc, r1     \n" // go nonsecure!
631                "1:                \n"
632                "mov    r0, sp     \n" // copy sp_mon to sp_svc
633                "cps    #0x13      \n" // switch to svc mode
634                "mov    sp, r0     \n"
635                "ldmia  sp!, {r0}  \n"
636                "ldmia  sp!, {fp}  \n"
637                : : "r" (r0), "r" (&go_nonsecure)
638                : "r2", "r3", "r4", "r5", "r6", "r7",
639                  "r8", "r9", "r10", "r12", "r14", "memory");
640 }
641
642 PUBLIC static inline
643 Mword
644 Cpu::tz_scr()
645 {
646   Mword r;
647   asm volatile ("mrc p15, 0, %0, c1, c1, 0" : "=r" (r));
648   return r;
649 }
650
651 PUBLIC static inline
652 void
653 Cpu::tz_scr(Mword val)
654 {
655   asm volatile ("mcr p15, 0, %0, c1, c1, 0" : : "r" (val));
656 }
657
658 PUBLIC static inline
659 Mword
660 Cpu::tz_mvbar()
661 {
662   Mword r;
663   asm volatile ("mrc p15, 0, %0, c12, c0, 1" : "=r" (r));
664   return r;
665 }
666
667 PUBLIC static inline
668 void
669 Cpu::tz_mvbar(Mword val)
670 {
671   asm volatile ("mcr p15, 0, %0, c12, c0, 1" : : "r" (val));
672 }
673
674 // ------------------------------------------------------------------------
675 IMPLEMENTATION [arm && tz && armca9]:
676
677 PUBLIC static inline
678 void
679 Cpu::enable_irq_ovrr()
680 {
681   // set IRQ/FIQ/Abort override bits
682   asm volatile("mov r0, #0x1c0            \n"
683                "mcr p15, 0, r0, c1, c1, 3 \n"
684                : : : "r0");
685 }
686
687 IMPLEMENTATION [!tz || !armca9]:
688
689 PUBLIC static inline
690 void
691 Cpu::enable_irq_ovrr()
692 {}
693
694 // ------------------------------------------------------------------------
695 IMPLEMENTATION [!debug]:
696
697 PRIVATE static inline
698 void
699 Cpu::print_infos()
700 {}
701
702 // ------------------------------------------------------------------------
703 IMPLEMENTATION [debug && armv6plus]:
704
705 PRIVATE
706 void
707 Cpu::id_print_infos()
708 {
709   printf("ID_PFR[01]:  %08lx %08lx", _cpu_id._pfr[0], _cpu_id._pfr[1]);
710   printf(" ID_[DA]FR0: %08lx %08lx\n", _cpu_id._dfr0, _cpu_id._afr0);
711   printf("ID_MMFR[04]: %08lx %08lx %08lx %08lx\n",
712          _cpu_id._mmfr[0], _cpu_id._mmfr[1], _cpu_id._mmfr[2], _cpu_id._mmfr[3]);
713 }
714
715 // ------------------------------------------------------------------------
716 IMPLEMENTATION [debug && !armv6plus]:
717
718 PRIVATE
719 void
720 Cpu::id_print_infos()
721 {
722 }
723
724 // ------------------------------------------------------------------------
725 IMPLEMENTATION [debug]:
726
727 PRIVATE
728 void
729 Cpu::print_infos()
730 {
731   printf("Cache config: %s\n", Config::Cache_enabled ? "ON" : "OFF");
732   id_print_infos();
733 }