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