1 // Copyright 2016 The Fuchsia Authors
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  * Main entry point to the OS. Initializes modules in order and creates
10  * the default thread.
11  */
12 #include <lk/main.h>
13 
14 #include <arch.h>
15 #include <debug.h>
16 #include <kernel/init.h>
17 #include <kernel/mutex.h>
18 #include <kernel/thread.h>
19 #include <lib/heap.h>
20 #include <lib/debuglog.h>
21 #include <lk/init.h>
22 #include <platform.h>
23 #include <string.h>
24 #include <target.h>
25 #include <vm/init.h>
26 #include <vm/vm.h>
27 #include <zircon/compiler.h>
28 
29 extern void (*const __init_array_start[])();
30 extern void (*const __init_array_end[])();
31 
32 static uint secondary_idle_thread_count;
33 
34 static int bootstrap2(void* arg);
35 
call_constructors()36 static void call_constructors() {
37     for (void (*const* a)() = __init_array_start; a != __init_array_end; a++)
38         (*a)();
39 }
40 
41 // called from arch code
lk_main()42 void lk_main() {
43     // serial prints to console based on compile time switch
44     dlog_bypass_init_early();
45 
46     // get us into some sort of thread context
47     thread_init_early();
48 
49     // deal with any static constructors
50     call_constructors();
51 
52     // early arch stuff
53     lk_primary_cpu_init_level(LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_ARCH_EARLY - 1);
54     arch_early_init();
55 
56     // do any super early platform initialization
57     lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH_EARLY, LK_INIT_LEVEL_PLATFORM_EARLY - 1);
58     platform_early_init();
59 
60     // do any super early target initialization
61     lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_LEVEL_TARGET_EARLY - 1);
62     target_early_init();
63 
64     dprintf(INFO, "\nwelcome to Zircon\n\n");
65 
66     dprintf(INFO, "KASLR: .text section at %p\n", __code_start);
67 
68     lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_VM_PREHEAP - 1);
69     dprintf(SPEW, "initializing vm pre-heap\n");
70     vm_init_preheap();
71 
72     // bring up the kernel heap
73     lk_primary_cpu_init_level(LK_INIT_LEVEL_VM_PREHEAP, LK_INIT_LEVEL_HEAP - 1);
74     dprintf(SPEW, "initializing heap\n");
75     heap_init();
76 
77     lk_primary_cpu_init_level(LK_INIT_LEVEL_HEAP, LK_INIT_LEVEL_VM - 1);
78     dprintf(SPEW, "initializing vm\n");
79     vm_init();
80 
81     // initialize the kernel
82     lk_primary_cpu_init_level(LK_INIT_LEVEL_VM, LK_INIT_LEVEL_KERNEL - 1);
83     dprintf(SPEW, "initializing kernel\n");
84     kernel_init();
85 
86     lk_primary_cpu_init_level(LK_INIT_LEVEL_KERNEL, LK_INIT_LEVEL_THREADING - 1);
87 
88     // create a thread to complete system initialization
89     dprintf(SPEW, "creating bootstrap completion thread\n");
90     thread_t* t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY);
91     thread_set_cpu_affinity(t, cpu_num_to_mask(0));
92     thread_detach(t);
93     thread_resume(t);
94 
95     // become the idle thread and enable interrupts to start the scheduler
96     thread_become_idle();
97 }
98 
bootstrap2(void *)99 static int bootstrap2(void*) {
100     dprintf(SPEW, "top of bootstrap2()\n");
101 
102     lk_primary_cpu_init_level(LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_ARCH - 1);
103     arch_init();
104 
105     // initialize the rest of the platform
106     dprintf(SPEW, "initializing platform\n");
107     lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH, LK_INIT_LEVEL_PLATFORM - 1);
108     platform_init();
109 
110     // initialize the target
111     dprintf(SPEW, "initializing target\n");
112     lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM, LK_INIT_LEVEL_TARGET - 1);
113     target_init();
114 
115     dprintf(SPEW, "moving to last init level\n");
116     lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET, LK_INIT_LEVEL_LAST);
117 
118     return 0;
119 }
120 
lk_secondary_cpu_entry()121 void lk_secondary_cpu_entry() {
122     uint cpu = arch_curr_cpu_num();
123 
124     if (cpu > secondary_idle_thread_count) {
125         dprintf(CRITICAL, "Invalid secondary cpu num %u, SMP_MAX_CPUS %d, secondary_idle_thread_count %u\n",
126                 cpu, SMP_MAX_CPUS, secondary_idle_thread_count);
127         return;
128     }
129 
130     // secondary cpu initialize from threading level up. 0 to threading was handled in arch
131     lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_LAST);
132 
133     dprintf(SPEW, "entering scheduler on cpu %u\n", cpu);
134     thread_secondary_cpu_entry();
135 }
136 
lk_init_secondary_cpus(uint secondary_cpu_count)137 void lk_init_secondary_cpus(uint secondary_cpu_count) {
138     if (secondary_cpu_count >= SMP_MAX_CPUS) {
139         dprintf(CRITICAL, "Invalid secondary_cpu_count %u, SMP_MAX_CPUS %d\n",
140                 secondary_cpu_count, SMP_MAX_CPUS);
141         secondary_cpu_count = SMP_MAX_CPUS - 1;
142     }
143     for (uint i = 0; i < secondary_cpu_count; i++) {
144         thread_t* t = thread_create_idle_thread(i + 1);
145         if (!t) {
146             dprintf(CRITICAL, "could not allocate idle thread %u\n", i + 1);
147             secondary_idle_thread_count = i;
148             break;
149         }
150     }
151     secondary_idle_thread_count = secondary_cpu_count;
152 }
153