53e1017720
* We started the "main2" thread too late. Since the scheduler was already started on all CPUs, the idle thread could wait (for a mutex) while spawing the "main2" thread. This violated the assumption in the scheduler that all idle threads would always be ready or running. We now create the thread while the kernel runs still single-threaded. * scheduler_start() is now invoked with interrupts still disabled. We enable them after the function returns. This prevents scheduler_reschedule() from potentially being invoked before scheduler_start(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29914 a95241bf-73f2-0310-859d-f6bbb57e9c96
342 lines
9.4 KiB
C++
342 lines
9.4 KiB
C++
/*
|
|
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
|
|
* Distributed under the terms of the MIT License.
|
|
*
|
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
|
* Distributed under the terms of the NewOS License.
|
|
*/
|
|
|
|
/*! This is main - initializes the kernel and launches the Bootscript */
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <FindDirectory.h>
|
|
#include <OS.h>
|
|
|
|
#include <arch/platform.h>
|
|
#include <boot_device.h>
|
|
#include <boot_item.h>
|
|
#include <boot_splash.h>
|
|
#include <cbuf.h>
|
|
#include <commpage.h>
|
|
#include <condition_variable.h>
|
|
#include <cpu.h>
|
|
#include <debug.h>
|
|
#include <elf.h>
|
|
#include <fs/devfs.h>
|
|
#include <fs/KPath.h>
|
|
#include <int.h>
|
|
#include <kdevice_manager.h>
|
|
#include <kdriver_settings.h>
|
|
#include <kernel_daemon.h>
|
|
#include <kmodule.h>
|
|
#include <kscheduler.h>
|
|
#include <ksyscalls.h>
|
|
#include <ksystem_info.h>
|
|
#include <lock.h>
|
|
#include <low_resource_manager.h>
|
|
#include <messaging.h>
|
|
#include <Notifications.h>
|
|
#include <port.h>
|
|
#include <posix/realtime_sem.h>
|
|
#include <posix/xsi_message_queue.h>
|
|
#include <posix/xsi_semaphore.h>
|
|
#include <real_time_clock.h>
|
|
#include <sem.h>
|
|
#include <smp.h>
|
|
#include <team.h>
|
|
#include <timer.h>
|
|
#include <user_debugger.h>
|
|
#include <vfs.h>
|
|
#include <vm.h>
|
|
#include <boot/kernel_args.h>
|
|
|
|
#include "vm/VMAnonymousCache.h"
|
|
|
|
|
|
//#define TRACE_BOOT
|
|
#ifdef TRACE_BOOT
|
|
# define TRACE(x...) dprintf("INIT: " x)
|
|
#else
|
|
# define TRACE(x...) ;
|
|
#endif
|
|
|
|
bool gKernelStartup = true;
|
|
|
|
static kernel_args sKernelArgs;
|
|
static uint32 sCpuRendezvous;
|
|
static uint32 sCpuRendezvous2;
|
|
|
|
static int32 main2(void *);
|
|
|
|
|
|
extern "C" int
|
|
_start(kernel_args *bootKernelArgs, int currentCPU)
|
|
{
|
|
if (bootKernelArgs->kernel_args_size != sizeof(kernel_args)
|
|
|| bootKernelArgs->version != CURRENT_KERNEL_ARGS_VERSION) {
|
|
// This is something we cannot handle right now - release kernels
|
|
// should always be able to handle the kernel_args of earlier
|
|
// released kernels.
|
|
debug_early_boot_message("Version mismatch between boot loader and "
|
|
"kernel!\n");
|
|
return -1;
|
|
}
|
|
|
|
smp_set_num_cpus(bootKernelArgs->num_cpus);
|
|
|
|
// wait for all the cpus to get here
|
|
smp_cpu_rendezvous(&sCpuRendezvous, currentCPU);
|
|
|
|
// the passed in kernel args are in a non-allocated range of memory
|
|
if (currentCPU == 0)
|
|
memcpy(&sKernelArgs, bootKernelArgs, sizeof(kernel_args));
|
|
|
|
smp_cpu_rendezvous(&sCpuRendezvous2, currentCPU);
|
|
|
|
// do any pre-booting cpu config
|
|
cpu_preboot_init_percpu(&sKernelArgs, currentCPU);
|
|
thread_preboot_init_percpu(&sKernelArgs, currentCPU);
|
|
|
|
// if we're not a boot cpu, spin here until someone wakes us up
|
|
if (smp_trap_non_boot_cpus(currentCPU)) {
|
|
// init platform
|
|
arch_platform_init(&sKernelArgs);
|
|
|
|
// setup debug output
|
|
debug_init(&sKernelArgs);
|
|
set_dprintf_enabled(true);
|
|
dprintf("Welcome to kernel debugger output!\n");
|
|
dprintf("Haiku revision: %lu\n", get_haiku_revision());
|
|
|
|
// init modules
|
|
TRACE("init CPU\n");
|
|
cpu_init(&sKernelArgs);
|
|
cpu_init_percpu(&sKernelArgs, currentCPU);
|
|
TRACE("init interrupts\n");
|
|
int_init(&sKernelArgs);
|
|
|
|
TRACE("init VM\n");
|
|
vm_init(&sKernelArgs);
|
|
// Before vm_init_post_sem() is called, we have to make sure that
|
|
// the boot loader allocated region is not used anymore
|
|
low_resource_manager_init();
|
|
|
|
// now we can use the heap and create areas
|
|
arch_platform_init_post_vm(&sKernelArgs);
|
|
lock_debug_init();
|
|
TRACE("init driver_settings\n");
|
|
boot_item_init();
|
|
driver_settings_init(&sKernelArgs);
|
|
debug_init_post_vm(&sKernelArgs);
|
|
TRACE("init notification services\n");
|
|
notifications_init();
|
|
TRACE("init teams\n");
|
|
team_init(&sKernelArgs);
|
|
TRACE("init ELF loader\n");
|
|
elf_init(&sKernelArgs);
|
|
TRACE("init modules\n");
|
|
module_init(&sKernelArgs);
|
|
TRACE("init semaphores\n");
|
|
haiku_sem_init(&sKernelArgs);
|
|
TRACE("init interrupts post vm\n");
|
|
int_init_post_vm(&sKernelArgs);
|
|
cpu_init_post_vm(&sKernelArgs);
|
|
commpage_init();
|
|
TRACE("init system info\n");
|
|
system_info_init(&sKernelArgs);
|
|
|
|
TRACE("init SMP\n");
|
|
smp_init(&sKernelArgs);
|
|
TRACE("init timer\n");
|
|
timer_init(&sKernelArgs);
|
|
TRACE("init real time clock\n");
|
|
rtc_init(&sKernelArgs);
|
|
|
|
TRACE("init condition variables\n");
|
|
condition_variable_init();
|
|
|
|
// now we can create and use semaphores
|
|
TRACE("init VM semaphores\n");
|
|
vm_init_post_sem(&sKernelArgs);
|
|
TRACE("init generic syscall\n");
|
|
generic_syscall_init();
|
|
smp_init_post_generic_syscalls();
|
|
TRACE("init cbuf\n");
|
|
cbuf_init();
|
|
TRACE("init scheduler\n");
|
|
scheduler_init();
|
|
TRACE("init threads\n");
|
|
thread_init(&sKernelArgs);
|
|
TRACE("init ports\n");
|
|
port_init(&sKernelArgs);
|
|
TRACE("init kernel daemons\n");
|
|
kernel_daemon_init();
|
|
arch_platform_init_post_thread(&sKernelArgs);
|
|
TRACE("init POSIX semaphores\n");
|
|
realtime_sem_init();
|
|
xsi_sem_init();
|
|
xsi_msg_init();
|
|
|
|
TRACE("init VM threads\n");
|
|
vm_init_post_thread(&sKernelArgs);
|
|
low_resource_manager_init_post_thread();
|
|
TRACE("init VFS\n");
|
|
vfs_init(&sKernelArgs);
|
|
#if ENABLE_SWAP_SUPPORT
|
|
TRACE("init swap support\n");
|
|
swap_init();
|
|
#endif
|
|
|
|
// Start a thread to finish initializing the rest of the system. Note,
|
|
// it won't be scheduled before calling scheduler_start() (on any CPU).
|
|
TRACE("spawning main2 thread\n");
|
|
thread_id thread = spawn_kernel_thread(&main2, "main2",
|
|
B_NORMAL_PRIORITY, NULL);
|
|
send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE);
|
|
|
|
// bring up the AP cpus in a lock step fashion
|
|
TRACE("waking up AP cpus\n");
|
|
sCpuRendezvous = sCpuRendezvous2 = 0;
|
|
smp_wake_up_non_boot_cpus();
|
|
smp_cpu_rendezvous(&sCpuRendezvous, 0); // wait until they're booted
|
|
|
|
// exit the kernel startup phase (mutexes, etc work from now on out)
|
|
TRACE("exiting kernel startup\n");
|
|
gKernelStartup = false;
|
|
|
|
smp_cpu_rendezvous(&sCpuRendezvous2, 0);
|
|
// release the AP cpus to go enter the scheduler
|
|
|
|
TRACE("starting scheduler on cpu 0 and enabling interrupts\n");
|
|
scheduler_start();
|
|
enable_interrupts();
|
|
} else {
|
|
// lets make sure we're in sync with the main cpu
|
|
// the boot processor has probably been sending us
|
|
// tlb sync messages all along the way, but we've
|
|
// been ignoring them
|
|
arch_cpu_global_TLB_invalidate();
|
|
|
|
// this is run for each non boot processor after they've been set loose
|
|
cpu_init_percpu(&sKernelArgs, currentCPU);
|
|
smp_per_cpu_init(&sKernelArgs, currentCPU);
|
|
|
|
// wait for all other AP cpus to get to this point
|
|
smp_cpu_rendezvous(&sCpuRendezvous, currentCPU);
|
|
smp_cpu_rendezvous(&sCpuRendezvous2, currentCPU);
|
|
|
|
// welcome to the machine
|
|
scheduler_start();
|
|
enable_interrupts();
|
|
}
|
|
|
|
TRACE("main: done... begin idle loop on cpu %d\n", currentCPU);
|
|
for (;;)
|
|
arch_cpu_idle();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int32
|
|
main2(void *unused)
|
|
{
|
|
(void)(unused);
|
|
|
|
TRACE("start of main2: initializing devices\n");
|
|
|
|
boot_splash_init(sKernelArgs.boot_splash);
|
|
|
|
TRACE("Init modules\n");
|
|
boot_splash_set_stage(BOOT_SPLASH_STAGE_1_INIT_MODULES);
|
|
module_init_post_threads();
|
|
|
|
// init userland debugging
|
|
TRACE("Init Userland debugging\n");
|
|
init_user_debug();
|
|
|
|
// init the messaging service
|
|
TRACE("Init Messaging Service\n");
|
|
init_messaging_service();
|
|
|
|
/* bootstrap all the filesystems */
|
|
TRACE("Bootstrap file systems\n");
|
|
boot_splash_set_stage(BOOT_SPLASH_STAGE_2_BOOTSTRAP_FS);
|
|
vfs_bootstrap_file_systems();
|
|
|
|
TRACE("Init Device Manager\n");
|
|
boot_splash_set_stage(BOOT_SPLASH_STAGE_3_INIT_DEVICES);
|
|
device_manager_init(&sKernelArgs);
|
|
|
|
TRACE("Add preloaded old-style drivers\n");
|
|
legacy_driver_add_preloaded(&sKernelArgs);
|
|
|
|
int_init_post_device_manager(&sKernelArgs);
|
|
|
|
TRACE("Mount boot file system\n");
|
|
boot_splash_set_stage(BOOT_SPLASH_STAGE_4_MOUNT_BOOT_FS);
|
|
vfs_mount_boot_file_system(&sKernelArgs);
|
|
|
|
#if ENABLE_SWAP_SUPPORT
|
|
TRACE("swap_init_post_modules\n");
|
|
swap_init_post_modules();
|
|
#endif
|
|
|
|
// CPU specific modules may now be available
|
|
boot_splash_set_stage(BOOT_SPLASH_STAGE_5_INIT_CPU_MODULES);
|
|
cpu_init_post_modules(&sKernelArgs);
|
|
|
|
TRACE("vm_init_post_modules\n");
|
|
boot_splash_set_stage(BOOT_SPLASH_STAGE_6_INIT_VM_MODULES);
|
|
vm_init_post_modules(&sKernelArgs);
|
|
|
|
TRACE("debug_init_post_modules\n");
|
|
debug_init_post_modules(&sKernelArgs);
|
|
|
|
TRACE("device_manager_init_post_modules\n");
|
|
device_manager_init_post_modules(&sKernelArgs);
|
|
|
|
boot_splash_set_stage(BOOT_SPLASH_STAGE_7_RUN_BOOT_SCRIPT);
|
|
boot_splash_uninit();
|
|
// NOTE: We could introduce a syscall to draw more icons indicating
|
|
// stages in the boot script itself. Then we should not free the image.
|
|
// In that case we should copy it over to the kernel heap, so that we
|
|
// can still free the kernel args.
|
|
|
|
// The boot splash screen is the last user of the kernel args.
|
|
// Note: don't confuse the kernel_args structure (which is never freed)
|
|
// with the kernel args ranges it contains (and which are freed here).
|
|
vm_free_kernel_args(&sKernelArgs);
|
|
|
|
// start the init process
|
|
{
|
|
KPath bootScriptPath;
|
|
status_t status = find_directory(B_BEOS_SYSTEM_DIRECTORY, gBootDevice,
|
|
false, bootScriptPath.LockBuffer(), bootScriptPath.BufferSize());
|
|
if (status != B_OK)
|
|
dprintf("main2: find_directory() failed: %s\n", strerror(status));
|
|
bootScriptPath.UnlockBuffer();
|
|
status = bootScriptPath.Append("boot/Bootscript");
|
|
if (status != B_OK) {
|
|
dprintf("main2: constructing path to Bootscript failed: "
|
|
"%s\n", strerror(status));
|
|
}
|
|
|
|
const char *args[] = { "/bin/sh", bootScriptPath.Path(), NULL };
|
|
int32 argc = 2;
|
|
thread_id thread;
|
|
|
|
thread = load_image(argc, args, NULL);
|
|
if (thread >= B_OK) {
|
|
resume_thread(thread);
|
|
TRACE("Bootscript started\n");
|
|
} else
|
|
dprintf("error starting \"%s\" error = %ld \n", args[0], thread);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|