1 /*
2 * Copyright (c) 2013-2015 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 /*
25 * Main entry point to the OS. Initializes modules in order and creates
26 * the default thread.
27 */
28 #include <compiler.h>
29 #include <debug.h>
30 #include <string.h>
31 #include <app.h>
32 #include <arch.h>
33 #include <platform.h>
34 #include <target.h>
35 #include <lib/heap.h>
36 #include <kernel/mutex.h>
37 #include <kernel/novm.h>
38 #include <kernel/thread.h>
39 #include <lk/init.h>
40 #include <lk/main.h>
41
42 /* saved boot arguments from whoever loaded the system */
43 ulong lk_boot_args[4];
44
45 extern void (*__ctor_list[])(void);
46 extern void (*__ctor_end[])(void);
47 extern int __bss_start;
48 extern int _end;
49
50 #if WITH_SMP
51 static thread_t *secondary_bootstrap_threads[SMP_MAX_CPUS - 1];
52 static uint secondary_bootstrap_thread_count;
53 #endif
54
55 static int bootstrap2(void *arg);
56
57 extern void kernel_init(void);
58
59 /* constructors inserted by clang for global C++ objects currently do not have
60 * CFI type info, so we have to disable this check until this is fixed */
61 __attribute__((no_sanitize("cfi", "kcfi")))
call_constructors(void)62 static void call_constructors(void)
63 {
64 void (**ctor)(void);
65
66 for (ctor = __ctor_list; ctor != __ctor_end; ctor++)
67 (*ctor)();
68 }
69
70 /* called from arch code */
lk_main(ulong arg0,ulong arg1,ulong arg2,ulong arg3)71 void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3)
72 {
73 // save the boot args
74 lk_boot_args[0] = arg0;
75 lk_boot_args[1] = arg1;
76 lk_boot_args[2] = arg2;
77 lk_boot_args[3] = arg3;
78
79 // get us into some sort of thread context
80 thread_init_early();
81
82 // early arch stuff
83 lk_primary_cpu_init_level(LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_ARCH_EARLY - 1);
84 arch_early_init();
85
86 // do any super early platform initialization
87 lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH_EARLY, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
88 platform_early_init();
89
90 // do any super early target initialization
91 lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_LEVEL_TARGET_EARLY - 1);
92 target_early_init();
93
94 #if WITH_SMP
95 dprintf(SPEW, "\nwelcome to lk/MP\n\n");
96 #else
97 dprintf(SPEW, "\nwelcome to lk\n\n");
98 #endif
99 dprintf(INFO, "boot args 0x%lx 0x%lx 0x%lx 0x%lx\n",
100 lk_boot_args[0], lk_boot_args[1], lk_boot_args[2], lk_boot_args[3]);
101
102 // bring up the kernel heap
103 lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1);
104 dprintf(SPEW, "initializing heap\n");
105 heap_init();
106
107 // deal with any static constructors
108 dprintf(SPEW, "calling constructors\n");
109 call_constructors();
110
111 // initialize the kernel
112 lk_primary_cpu_init_level(LK_INIT_LEVEL_HEAP, LK_INIT_LEVEL_KERNEL - 1);
113 kernel_init();
114
115 lk_primary_cpu_init_level(LK_INIT_LEVEL_KERNEL, LK_INIT_LEVEL_THREADING - 1);
116
117 // create a thread to complete system initialization
118 dprintf(SPEW, "creating bootstrap completion thread\n");
119 thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
120 if (!t) {
121 panic("Failed to start bootstrap completion thread\n");
122 }
123 thread_set_pinned_cpu(t, 0);
124 thread_detach(t);
125 thread_resume(t);
126
127 // become the idle thread and enable interrupts to start the scheduler
128 thread_become_idle();
129 }
130
bootstrap2(void * arg)131 static int bootstrap2(void *arg)
132 {
133 dprintf(SPEW, "top of bootstrap2()\n");
134
135 lk_primary_cpu_init_level(LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_ARCH - 1);
136 arch_init();
137
138 // initialize the rest of the platform
139 dprintf(SPEW, "initializing platform\n");
140 lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH, LK_INIT_LEVEL_PLATFORM - 1);
141 platform_init();
142
143 // initialize the target
144 dprintf(SPEW, "initializing target\n");
145 lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM, LK_INIT_LEVEL_TARGET - 1);
146 target_init();
147
148 dprintf(SPEW, "calling apps_init()\n");
149 lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET, LK_INIT_LEVEL_APPS - 1);
150 apps_init();
151
152 lk_primary_cpu_init_level(LK_INIT_LEVEL_APPS, LK_INIT_LEVEL_LAST);
153
154 return 0;
155 }
156
157 #if WITH_SMP
lk_secondary_cpu_entry(void)158 void lk_secondary_cpu_entry(void)
159 {
160 uint cpu = arch_curr_cpu_num();
161
162 if (cpu > secondary_bootstrap_thread_count) {
163 dprintf(CRITICAL, "Invalid secondary cpu num %d, SMP_MAX_CPUS %d, secondary_bootstrap_thread_count %d\n",
164 cpu, SMP_MAX_CPUS, secondary_bootstrap_thread_count);
165 return;
166 }
167
168 thread_secondary_cpu_init_early();
169 thread_resume(secondary_bootstrap_threads[cpu - 1]);
170
171 dprintf(SPEW, "entering scheduler on cpu %d\n", cpu);
172 thread_secondary_cpu_entry();
173 }
174
secondary_cpu_bootstrap2(void * arg)175 static int secondary_cpu_bootstrap2(void *arg)
176 {
177 /* secondary cpu initialize from threading level up. 0 to threading was handled in arch */
178 lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_LAST);
179
180 return 0;
181 }
182
lk_init_secondary_cpus(uint secondary_cpu_count)183 void lk_init_secondary_cpus(uint secondary_cpu_count)
184 {
185 if (secondary_cpu_count >= SMP_MAX_CPUS) {
186 dprintf(CRITICAL, "Invalid secondary_cpu_count %u, SMP_MAX_CPUS %d\n",
187 secondary_cpu_count, SMP_MAX_CPUS);
188 secondary_cpu_count = SMP_MAX_CPUS - 1;
189 }
190 for (uint i = 0; i < secondary_cpu_count; i++) {
191 dprintf(SPEW, "creating bootstrap completion thread for cpu %d\n", i + 1);
192 thread_t *t = thread_create("secondarybootstrap2",
193 &secondary_cpu_bootstrap2, NULL,
194 DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
195 if (!t) {
196 dprintf(CRITICAL,
197 "Failed to start bootstrap completion thread for cpu %d\n",
198 i + 1);
199 return;
200 }
201 t->pinned_cpu = i + 1;
202 thread_detach(t);
203 secondary_bootstrap_threads[i] = t;
204 }
205 secondary_bootstrap_thread_count = secondary_cpu_count;
206 }
207 #endif
208