1/*
2 * Copyright 2018, J��r��me Duval, jerome.duval@gmail.com.
3 * Copyright 2002-2020, Axel D��rfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
5 *
6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
9
10
11/*! This is main - initializes the kernel and launches the launch_daemon */
12
13
14#include <string.h>
15
16#include <FindDirectory.h>
17#include <OS.h>
18
19#include <arch/platform.h>
20#include <boot_device.h>
21#include <boot_item.h>
22#include <boot_splash.h>
23#include <commpage.h>
24#ifdef _COMPAT_MODE
25#	include <commpage_compat.h>
26#endif
27#include <condition_variable.h>
28#include <cpu.h>
29#include <debug.h>
30#include <DPC.h>
31#include <elf.h>
32#include <find_directory_private.h>
33#include <fs/devfs.h>
34#include <fs/KPath.h>
35#include <int.h>
36#include <kdevice_manager.h>
37#include <kdriver_settings.h>
38#include <kernel_daemon.h>
39#include <kmodule.h>
40#include <kscheduler.h>
41#include <ksyscalls.h>
42#include <ksystem_info.h>
43#include <lock.h>
44#include <low_resource_manager.h>
45#include <messaging.h>
46#include <Notifications.h>
47#include <port.h>
48#include <posix/realtime_sem.h>
49#include <posix/xsi_message_queue.h>
50#include <posix/xsi_semaphore.h>
51#include <real_time_clock.h>
52#include <sem.h>
53#include <smp.h>
54#include <stack_protector.h>
55#include <system_profiler.h>
56#include <team.h>
57#include <timer.h>
58#include <user_debugger.h>
59#include <user_mutex.h>
60#include <vfs.h>
61#include <vm/vm.h>
62#include <boot/kernel_args.h>
63
64#include "vm/VMAnonymousCache.h"
65
66
67//#define TRACE_BOOT
68#ifdef TRACE_BOOT
69#	define TRACE(x...) dprintf("INIT: " x)
70#else
71#	define TRACE(x...) ;
72#endif
73
74
75void *__dso_handle;
76
77bool gKernelStartup = true;
78bool gKernelShutdown = false;
79
80static kernel_args sKernelArgs;
81static uint32 sCpuRendezvous;
82static uint32 sCpuRendezvous2;
83static uint32 sCpuRendezvous3;
84
85static int32 main2(void *);
86
87
88static void
89non_boot_cpu_init(void* args, int currentCPU)
90{
91	kernel_args* kernelArgs = (kernel_args*)args;
92	if (currentCPU != 0)
93		cpu_init_percpu(kernelArgs, currentCPU);
94}
95
96
97extern "C" int
98_start(kernel_args *bootKernelArgs, int currentCPU)
99{
100	if (bootKernelArgs->version == CURRENT_KERNEL_ARGS_VERSION
101		&& bootKernelArgs->kernel_args_size == kernel_args_size_v1) {
102		sKernelArgs.ucode_data = NULL;
103		sKernelArgs.ucode_data_size = 0;
104	} else if (bootKernelArgs->kernel_args_size != sizeof(kernel_args)
105		|| bootKernelArgs->version != CURRENT_KERNEL_ARGS_VERSION) {
106		// This is something we cannot handle right now - release kernels
107		// should always be able to handle the kernel_args of earlier
108		// released kernels.
109		debug_early_boot_message("Version mismatch between boot loader and "
110			"kernel!\n");
111		return -1;
112	}
113
114	smp_set_num_cpus(bootKernelArgs->num_cpus);
115
116	// wait for all the cpus to get here
117	smp_cpu_rendezvous(&sCpuRendezvous);
118
119	// the passed in kernel args are in a non-allocated range of memory
120	if (currentCPU == 0)
121		memcpy(&sKernelArgs, bootKernelArgs, bootKernelArgs->kernel_args_size);
122
123	smp_cpu_rendezvous(&sCpuRendezvous2);
124
125	// do any pre-booting cpu config
126	cpu_preboot_init_percpu(&sKernelArgs, currentCPU);
127	thread_preboot_init_percpu(&sKernelArgs, currentCPU);
128
129	// if we're not a boot cpu, spin here until someone wakes us up
130	if (smp_trap_non_boot_cpus(currentCPU, &sCpuRendezvous3)) {
131		// init platform
132		arch_platform_init(&sKernelArgs);
133
134		// setup debug output
135		debug_init(&sKernelArgs);
136		set_dprintf_enabled(true);
137		dprintf("Welcome to kernel debugger output!\n");
138		dprintf("Haiku revision: %s, debug level: %d\n", get_haiku_revision(),
139			KDEBUG_LEVEL);
140
141		// init modules
142		TRACE("init CPU\n");
143		cpu_init(&sKernelArgs);
144		cpu_init_percpu(&sKernelArgs, currentCPU);
145		TRACE("init interrupts\n");
146		int_init(&sKernelArgs);
147
148		TRACE("init VM\n");
149		vm_init(&sKernelArgs);
150			// Before vm_init_post_sem() is called, we have to make sure that
151			// the boot loader allocated region is not used anymore
152		boot_item_init();
153		debug_init_post_vm(&sKernelArgs);
154		low_resource_manager_init();
155
156		// now we can use the heap and create areas
157		arch_platform_init_post_vm(&sKernelArgs);
158		lock_debug_init();
159		TRACE("init driver_settings\n");
160		driver_settings_init(&sKernelArgs);
161		debug_init_post_settings(&sKernelArgs);
162		TRACE("init notification services\n");
163		notifications_init();
164		TRACE("init teams\n");
165		team_init(&sKernelArgs);
166		TRACE("init ELF loader\n");
167		elf_init(&sKernelArgs);
168		TRACE("init modules\n");
169		module_init(&sKernelArgs);
170		TRACE("init semaphores\n");
171		haiku_sem_init(&sKernelArgs);
172		TRACE("init interrupts post vm\n");
173		int_init_post_vm(&sKernelArgs);
174		cpu_init_post_vm(&sKernelArgs);
175		commpage_init();
176#ifdef _COMPAT_MODE
177		commpage_compat_init();
178#endif
179		call_all_cpus_sync(non_boot_cpu_init, &sKernelArgs);
180
181		TRACE("init system info\n");
182		system_info_init(&sKernelArgs);
183
184		TRACE("init SMP\n");
185		smp_init(&sKernelArgs);
186		cpu_build_topology_tree();
187		TRACE("init timer\n");
188		timer_init(&sKernelArgs);
189		TRACE("init real time clock\n");
190		rtc_init(&sKernelArgs);
191		timer_init_post_rtc();
192
193		TRACE("init condition variables\n");
194		condition_variable_init();
195
196		// now we can create and use semaphores
197		TRACE("init VM semaphores\n");
198		vm_init_post_sem(&sKernelArgs);
199		TRACE("init generic syscall\n");
200		generic_syscall_init();
201		smp_init_post_generic_syscalls();
202		TRACE("init scheduler\n");
203		scheduler_init();
204		TRACE("init threads\n");
205		thread_init(&sKernelArgs);
206		TRACE("init kernel daemons\n");
207		kernel_daemon_init();
208		TRACE("init stack protector\n");
209		stack_protector_init();
210		arch_platform_init_post_thread(&sKernelArgs);
211
212		TRACE("init I/O interrupts\n");
213		int_init_io(&sKernelArgs);
214		TRACE("init VM threads\n");
215		vm_init_post_thread(&sKernelArgs);
216		low_resource_manager_init_post_thread();
217		TRACE("init DPC\n");
218		dpc_init();
219		TRACE("init VFS\n");
220		vfs_init(&sKernelArgs);
221#if ENABLE_SWAP_SUPPORT
222		TRACE("init swap support\n");
223		swap_init();
224#endif
225		TRACE("init POSIX semaphores\n");
226		realtime_sem_init();
227		xsi_sem_init();
228		xsi_msg_init();
229
230		// Start a thread to finish initializing the rest of the system. Note,
231		// it won't be scheduled before calling scheduler_start() (on any CPU).
232		TRACE("spawning main2 thread\n");
233		thread_id thread = spawn_kernel_thread(&main2, "main2",
234			B_NORMAL_PRIORITY, NULL);
235		resume_thread(thread);
236
237		// We're ready to start the scheduler and enable interrupts on all CPUs.
238		scheduler_enable_scheduling();
239
240		// bring up the AP cpus in a lock step fashion
241		TRACE("waking up AP cpus\n");
242		sCpuRendezvous = sCpuRendezvous2 = 0;
243		smp_wake_up_non_boot_cpus();
244		smp_cpu_rendezvous(&sCpuRendezvous); // wait until they're booted
245
246		// exit the kernel startup phase (mutexes, etc work from now on out)
247		TRACE("exiting kernel startup\n");
248		gKernelStartup = false;
249
250		smp_cpu_rendezvous(&sCpuRendezvous2);
251			// release the AP cpus to go enter the scheduler
252
253		TRACE("starting scheduler on cpu 0 and enabling interrupts\n");
254		scheduler_start();
255		enable_interrupts();
256	} else {
257		// lets make sure we're in sync with the main cpu
258		// the boot processor has probably been sending us
259		// tlb sync messages all along the way, but we've
260		// been ignoring them
261		arch_cpu_global_TLB_invalidate();
262
263		// this is run for each non boot processor after they've been set loose
264		smp_per_cpu_init(&sKernelArgs, currentCPU);
265
266		// wait for all other AP cpus to get to this point
267		smp_cpu_rendezvous(&sCpuRendezvous);
268		smp_cpu_rendezvous(&sCpuRendezvous2);
269
270		// welcome to the machine
271		scheduler_start();
272		enable_interrupts();
273	}
274
275#ifdef TRACE_BOOT
276	// We disable interrupts for this dprintf(), since otherwise dprintf()
277	// would acquires a mutex, which is something we must not do in an idle
278	// thread, or otherwise the scheduler would be seriously unhappy.
279	disable_interrupts();
280	TRACE("main: done... begin idle loop on cpu %d\n", currentCPU);
281	enable_interrupts();
282#endif
283
284	for (;;)
285		cpu_idle();
286
287	return 0;
288}
289
290
291static int32
292main2(void* /*unused*/)
293{
294	TRACE("start of main2: initializing devices\n");
295
296#if SYSTEM_PROFILER
297	start_system_profiler(SYSTEM_PROFILE_SIZE, SYSTEM_PROFILE_STACK_DEPTH,
298		SYSTEM_PROFILE_INTERVAL);
299#endif
300	boot_splash_init(sKernelArgs.boot_splash);
301
302	commpage_init_post_cpus();
303#ifdef _COMPAT_MODE
304	commpage_compat_init_post_cpus();
305#endif
306
307	TRACE("init ports\n");
308	port_init(&sKernelArgs);
309
310	TRACE("init user mutex\n");
311	user_mutex_init();
312
313	TRACE("init system notifications\n");
314	system_notifications_init();
315
316	TRACE("Init modules\n");
317	boot_splash_set_stage(BOOT_SPLASH_STAGE_1_INIT_MODULES);
318	module_init_post_threads();
319
320	// init userland debugging
321	TRACE("Init Userland debugging\n");
322	init_user_debug();
323
324	// init the messaging service
325	TRACE("Init Messaging Service\n");
326	init_messaging_service();
327
328	/* bootstrap all the filesystems */
329	TRACE("Bootstrap file systems\n");
330	boot_splash_set_stage(BOOT_SPLASH_STAGE_2_BOOTSTRAP_FS);
331	vfs_bootstrap_file_systems();
332
333	TRACE("Init Device Manager\n");
334	boot_splash_set_stage(BOOT_SPLASH_STAGE_3_INIT_DEVICES);
335	device_manager_init(&sKernelArgs);
336
337	TRACE("Add preloaded old-style drivers\n");
338	legacy_driver_add_preloaded(&sKernelArgs);
339
340	int_init_post_device_manager(&sKernelArgs);
341
342	TRACE("Mount boot file system\n");
343	boot_splash_set_stage(BOOT_SPLASH_STAGE_4_MOUNT_BOOT_FS);
344	vfs_mount_boot_file_system(&sKernelArgs);
345
346#if ENABLE_SWAP_SUPPORT
347	TRACE("swap_init_post_modules\n");
348	swap_init_post_modules();
349#endif
350
351	// CPU specific modules may now be available
352	boot_splash_set_stage(BOOT_SPLASH_STAGE_5_INIT_CPU_MODULES);
353	cpu_init_post_modules(&sKernelArgs);
354
355	TRACE("vm_init_post_modules\n");
356	boot_splash_set_stage(BOOT_SPLASH_STAGE_6_INIT_VM_MODULES);
357	vm_init_post_modules(&sKernelArgs);
358
359	TRACE("debug_init_post_modules\n");
360	debug_init_post_modules(&sKernelArgs);
361
362	TRACE("device_manager_init_post_modules\n");
363	device_manager_init_post_modules(&sKernelArgs);
364
365	boot_splash_set_stage(BOOT_SPLASH_STAGE_7_RUN_BOOT_SCRIPT);
366	boot_splash_uninit();
367		// NOTE: We could introduce a syscall to draw more icons indicating
368		// stages in the boot script itself. Then we should not free the image.
369		// In that case we should copy it over to the kernel heap, so that we
370		// can still free the kernel args.
371
372	// The boot splash screen is the last user of the kernel args.
373	// Note: don't confuse the kernel_args structure (which is never freed)
374	// with the kernel args ranges it contains (and which are freed here).
375	vm_free_kernel_args(&sKernelArgs);
376
377	// start the init process
378	{
379		KPath serverPath;
380		status_t status = __find_directory(B_SYSTEM_SERVERS_DIRECTORY,
381			gBootDevice, false, serverPath.LockBuffer(),
382			serverPath.BufferSize());
383		if (status != B_OK)
384			dprintf("main2: find_directory() failed: %s\n", strerror(status));
385		serverPath.UnlockBuffer();
386		status = serverPath.Append("/launch_daemon");
387		if (status != B_OK) {
388			dprintf("main2: constructing path to launch_daemon failed: %s\n",
389			strerror(status));
390		}
391
392		const char* args[] = { serverPath.Path(), NULL };
393		int32 argc = 1;
394		thread_id thread;
395
396		thread = load_image(argc, args, NULL);
397		if (thread >= B_OK) {
398			resume_thread(thread);
399			TRACE("launch_daemon started\n");
400		} else {
401			dprintf("error starting \"%s\" error = %" B_PRId32 " \n",
402				args[0], thread);
403		}
404	}
405
406	return 0;
407}
408
409