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