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
29extern void (*const __init_array_start[])();
30extern void (*const __init_array_end[])();
31
32static uint secondary_idle_thread_count;
33
34static int bootstrap2(void* arg);
35
36static 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
42void 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
99static 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
121void 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
137void 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