]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/kernel_thread-ia32.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / kernel_thread-ia32.cpp
1
2 IMPLEMENTATION[ia32,amd64]:
3
4 #include "apic.h"
5 #include "config.h"
6 #include "cpu.h"
7 #include "io_apic.h"
8 #include "irq_chip.h"
9 #include "koptions.h"
10 #include "mem_layout.h"
11 #include "pic.h"
12 #include "profile.h"
13 #include "trap_state.h"
14 #include "watchdog.h"
15
16 IMPLEMENT inline NEEDS["mem_layout.h"]
17 void
18 Kernel_thread::free_initcall_section()
19 {
20   // just fill up with invalid opcodes
21   for (unsigned short *i = (unsigned short *) &Mem_layout::initcall_start;   
22                        i < (unsigned short *) &Mem_layout::initcall_end; i++)
23     *i = 0x0b0f;        // UD2 opcode
24 }
25
26
27 IMPLEMENT FIASCO_INIT
28 void
29 Kernel_thread::bootstrap_arch()
30 {
31   // 
32   // install our slow trap handler
33   //
34   nested_trap_handler      = Trap_state::base_handler;
35   Trap_state::base_handler = thread_handle_trap;
36
37   //
38   // initialize interrupts
39   //
40   if (!Io_apic::active())
41     {
42       Irq_chip::hw_chip->reserve(2);            // reserve cascade irq
43       Pic::enable_locked(2);                    // allow cascaded irqs
44     }
45
46   // initialize the profiling timer
47   bool user_irq0 = Koptions::o()->opt(Koptions::F_irq0);
48
49   if (Config::scheduler_mode == Config::SCHED_PIT && user_irq0)
50     panic("option -irq0 not possible since irq 0 is used for scheduling");
51
52   if (Config::profiling)
53     {
54       if (user_irq0)
55         panic("options -profile and -irq0 don't mix");
56       if (Config::scheduler_mode == Config::SCHED_PIT)
57         panic("option -profile' not available since PIT is used as "
58               "source for timer tick");
59
60       Irq_chip::hw_chip->reserve(0); // reserve IRQ 0
61       Profile::init();
62       if (Koptions::o()->opt(Koptions::F_profstart))
63         Profile::start();
64     }
65   else
66     {
67       if (!Io_apic::active() && !user_irq0
68           && !Config::scheduler_mode == Config::SCHED_PIT)
69         Irq_chip::hw_chip->reserve(0); // reserve irq0 even though
70     }
71
72   boot_app_cpus();
73 }
74
75 //--------------------------------------------------------------------------
76 IMPLEMENTATION [!mp]:
77
78 static void inline
79 Kernel_thread::boot_app_cpus()
80 {}
81
82
83 //--------------------------------------------------------------------------
84 IMPLEMENTATION [mp && amd64]:
85
86 PRIVATE inline NOEXPORT
87 static Address
88 Kernel_thread::get_startup_pbdr()
89 {
90   // for amd64 we need to make sure that our boot-up page directory is below
91   // 4GB in physical memory
92   static char _boot_pdir_page[Config::PAGE_SIZE] __attribute__((aligned(4096)));
93   memcpy(_boot_pdir_page, Kmem::dir(), sizeof(_boot_pdir_page));
94
95   return Kmem::virt_to_phys(_boot_pdir_page);
96 }
97
98 //--------------------------------------------------------------------------
99 IMPLEMENTATION [mp && ia32]:
100
101 PRIVATE inline NOEXPORT
102 static Address
103 Kernel_thread::get_startup_pbdr()
104 {
105   return Mem_layout::pmem_to_phys(Kmem::dir());
106 }
107
108 //--------------------------------------------------------------------------
109 IMPLEMENTATION [mp]:
110
111 static void
112 Kernel_thread::boot_app_cpus()
113 {
114   // sending (INIT-)IPIs on non-MP systems might not work
115   if (   Cpu::boot_cpu()->vendor() == Cpu::Vendor_amd
116       && Cpu::amd_cpuid_mnc() < 2)
117     return;
118
119   // where to start the APs for detection of the APIC-IDs
120   extern char _tramp_mp_entry[];
121
122   // feature enabling flags (esp. cache enabled flag and paging enabled flag)
123   extern volatile Mword _tramp_mp_startup_cr0;
124
125   // feature enabling flags (esp. needed for big pages)
126   extern volatile Mword _tramp_mp_startup_cr4;
127
128   // physical address of the page table directory to use
129   extern volatile Address _tramp_mp_startup_pdbr;
130
131   // pseudo descriptor for the gdt to load
132   extern Pseudo_descriptor _tramp_mp_startup_gdt_pdesc;
133
134   Address tramp_page;
135
136   _tramp_mp_startup_pdbr = get_startup_pbdr();
137   _tramp_mp_startup_cr4 = Cpu::get_cr4();
138   _tramp_mp_startup_cr0 = Cpu::get_cr0();
139   _tramp_mp_startup_gdt_pdesc
140     = Pseudo_descriptor((Address)Cpu::boot_cpu()->get_gdt(), Gdt::gdt_max -1);
141
142   __asm__ __volatile__ ("" : : : "memory");
143
144   // Say what we do
145   printf("MP: detecting APs...\n");
146
147   // broadcast an AP startup via the APIC (let run the self-registration code)
148   tramp_page = (Address)&(_tramp_mp_entry[0]);
149
150   // Send IPI-Sequency to startup the APs
151   Apic::mp_startup(Cpu::boot_cpu(), Apic::APIC_IPI_OTHERS, tramp_page);
152 }