1 /*
2 * Copyright (c) 2013-2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 /*
10 * Main entry point to the OS. Initializes modules in order and creates
11 * the default thread.
12 */
13 #include <lk/main.h>
14
15 #include <app.h>
16 #include <arch.h>
17 #include <kernel/init.h>
18 #include <kernel/mutex.h>
19 #include <kernel/novm.h>
20 #include <kernel/thread.h>
21 #include <lib/heap.h>
22 #include <lk/compiler.h>
23 #include <lk/debug.h>
24 #include <lk/init.h>
25 #include <platform.h>
26 #include <string.h>
27 #include <target.h>
28
29 /* saved boot arguments from whoever loaded the system */
30 ulong lk_boot_args[4];
31
32 extern void *__ctor_list;
33 extern void *__ctor_end;
34 extern int __bss_start;
35 extern int _end;
36
37 #if WITH_SMP
38 static thread_t *secondary_bootstrap_threads[SMP_MAX_CPUS - 1];
39 static uint secondary_bootstrap_thread_count;
40 #endif
41
42 static int bootstrap2(void *arg);
43
call_constructors(void)44 static void call_constructors(void) {
45 void **ctor;
46
47 ctor = &__ctor_list;
48 while (ctor != &__ctor_end) {
49 void (*func)(void);
50
51 func = (void ( *)(void))*ctor;
52
53 func();
54 ctor++;
55 }
56 }
57
58 /* called from arch code */
lk_main(ulong arg0,ulong arg1,ulong arg2,ulong arg3)59 void lk_main(ulong arg0, ulong arg1, ulong arg2, ulong arg3) {
60 // save the boot args
61 lk_boot_args[0] = arg0;
62 lk_boot_args[1] = arg1;
63 lk_boot_args[2] = arg2;
64 lk_boot_args[3] = arg3;
65
66 // get us into some sort of thread context
67 thread_init_early();
68
69 // early arch stuff
70 lk_primary_cpu_init_level(LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_ARCH_EARLY - 1);
71 arch_early_init();
72
73 // do any super early platform initialization
74 lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH_EARLY, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
75 platform_early_init();
76
77 // do any super early target initialization
78 lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_LEVEL_TARGET_EARLY - 1);
79 target_early_init();
80
81 #if WITH_SMP
82 dprintf(INFO, "\nwelcome to lk/MP\n\n");
83 #else
84 dprintf(INFO, "\nwelcome to lk\n\n");
85 #endif
86 dprintf(INFO, "boot args 0x%lx 0x%lx 0x%lx 0x%lx\n",
87 lk_boot_args[0], lk_boot_args[1], lk_boot_args[2], lk_boot_args[3]);
88
89 // bring up the kernel heap
90 lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1);
91 dprintf(SPEW, "initializing heap\n");
92 heap_init();
93
94 // deal with any static constructors
95 dprintf(SPEW, "calling constructors\n");
96 call_constructors();
97
98 // initialize the kernel
99 lk_primary_cpu_init_level(LK_INIT_LEVEL_HEAP, LK_INIT_LEVEL_KERNEL - 1);
100 kernel_init();
101
102 lk_primary_cpu_init_level(LK_INIT_LEVEL_KERNEL, LK_INIT_LEVEL_THREADING - 1);
103
104 // create a thread to complete system initialization
105 dprintf(SPEW, "creating bootstrap completion thread\n");
106 thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
107 thread_set_pinned_cpu(t, 0);
108 thread_detach(t);
109 thread_resume(t);
110
111 // become the idle thread and enable interrupts to start the scheduler
112 thread_become_idle();
113 }
114
bootstrap2(void * arg)115 static int bootstrap2(void *arg) {
116 dprintf(SPEW, "top of bootstrap2()\n");
117
118 lk_primary_cpu_init_level(LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_ARCH - 1);
119 arch_init();
120
121 // initialize the rest of the platform
122 dprintf(SPEW, "initializing platform\n");
123 lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH, LK_INIT_LEVEL_PLATFORM - 1);
124 platform_init();
125
126 // initialize the target
127 dprintf(SPEW, "initializing target\n");
128 lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM, LK_INIT_LEVEL_TARGET - 1);
129 target_init();
130
131 dprintf(SPEW, "initializing apps\n");
132 lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET, LK_INIT_LEVEL_APPS - 1);
133 apps_init();
134
135 lk_primary_cpu_init_level(LK_INIT_LEVEL_APPS, LK_INIT_LEVEL_LAST);
136
137 return 0;
138 }
139
140 #if WITH_SMP
lk_secondary_cpu_entry(void)141 void lk_secondary_cpu_entry(void) {
142 uint cpu = arch_curr_cpu_num();
143
144 if (cpu > secondary_bootstrap_thread_count) {
145 dprintf(CRITICAL, "Invalid secondary cpu num %d, SMP_MAX_CPUS %d, secondary_bootstrap_thread_count %d\n",
146 cpu, SMP_MAX_CPUS, secondary_bootstrap_thread_count);
147 return;
148 }
149
150 thread_secondary_cpu_init_early();
151 thread_resume(secondary_bootstrap_threads[cpu - 1]);
152
153 dprintf(SPEW, "entering scheduler on cpu %d\n", cpu);
154 thread_secondary_cpu_entry();
155 }
156
secondary_cpu_bootstrap2(void * arg)157 static int secondary_cpu_bootstrap2(void *arg) {
158 /* secondary cpu initialize from threading level up. 0 to threading was handled in arch */
159 lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_LAST);
160
161 return 0;
162 }
163
lk_init_secondary_cpus(uint secondary_cpu_count)164 void lk_init_secondary_cpus(uint secondary_cpu_count) {
165 if (secondary_cpu_count >= SMP_MAX_CPUS) {
166 dprintf(CRITICAL, "Invalid secondary_cpu_count %d, SMP_MAX_CPUS %d\n",
167 secondary_cpu_count, SMP_MAX_CPUS);
168 secondary_cpu_count = SMP_MAX_CPUS - 1;
169 }
170 for (uint i = 0; i < secondary_cpu_count; i++) {
171 dprintf(SPEW, "creating bootstrap completion thread for cpu %d\n", i + 1);
172 thread_t *t = thread_create("secondarybootstrap2",
173 &secondary_cpu_bootstrap2, NULL,
174 DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
175 t->pinned_cpu = i + 1;
176 thread_detach(t);
177 secondary_bootstrap_threads[i] = t;
178 }
179 secondary_bootstrap_thread_count = secondary_cpu_count;
180 }
181 #endif
182