diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index d90a2d16..c2c29fda 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -428,6 +429,70 @@ static void SystemIdleThread(void* /*user*/) } } +kthread_mutex_t driver_threads_lock = KTHREAD_MUTEX_INITIALIZER; +kthread_cond_t driver_threads_cond = KTHREAD_COND_INITIALIZER; +size_t driver_threads_done = 0; +size_t driver_threads_total = 0; + +// Parallelize the initialization of slow drivers. +static void RunDriverThread(void (*entry)(void*), void* user, const char* name) +{ + kthread_mutex_lock(&driver_threads_lock); + driver_threads_total++; + kthread_mutex_unlock(&driver_threads_lock); + if ( !RunKernelThread(entry, user, name) ) + PanicF("RunKernelThread: %s", name); +} + +static void FinishedDriverThread() +{ + ScopedLock lock(&driver_threads_lock); + driver_threads_done++; + kthread_cond_broadcast(&driver_threads_cond); +} + +struct PS2ThreadCtx +{ + PS2Keyboard* keyboard; + PS2Mouse* mouse; +}; + +static void PS2Thread(void* user) +{ + struct PS2ThreadCtx* ctx = (struct PS2ThreadCtx*) user; + PS2::Init(ctx->keyboard, ctx->mouse); + FinishedDriverThread(); +} + +struct DevCtx +{ + Ref dev; +}; + +static void AHCIThread(void* user) +{ + AHCI::Init("/dev", ((struct DevCtx*) user)->dev); + FinishedDriverThread(); +} + +static void ATAThread(void* user) +{ + ATA::Init("/dev", ((struct DevCtx*) user)->dev); + FinishedDriverThread(); +} + +static void BGAThread(void* /*user*/) +{ + BGA::Init(); + FinishedDriverThread(); +} + +static void EMThread(void* user) +{ + EM::Init("/dev", ((struct DevCtx*) user)->dev); + FinishedDriverThread(); +} + static void BootThread(void* /*user*/) { // @@ -511,6 +576,7 @@ static void BootThread(void* /*user*/) Ref slashdev = droot->open(&ctx, "dev", O_READ | O_DIRECTORY); if ( !slashdev ) Panic("Unable to create descriptor for RAM filesystem /dev directory."); + struct DevCtx dev_ctx = { slashdev }; // Initialize the keyboard. PS2Keyboard* keyboard = new PS2Keyboard(); @@ -528,7 +594,8 @@ static void BootThread(void* /*user*/) Panic("Could not allocate PS2 Mouse driver"); // Initialize the PS/2 controller. - PS2::Init(keyboard, mouse); + struct PS2ThreadCtx ps2_context = { keyboard, mouse }; + RunDriverThread(PS2Thread, &ps2_context, "ps2"); // Register /dev/tty as the current-terminal factory. Ref tty(new DevTTY(slashdev->dev, 0666, 0, 0)); @@ -616,13 +683,13 @@ static void BootThread(void* /*user*/) #endif // Initialize AHCI devices. - AHCI::Init("/dev", slashdev); + RunDriverThread(AHCIThread, &dev_ctx, "ahci"); // Initialize ATA devices. - ATA::Init("/dev", slashdev); + RunDriverThread(ATAThread, &dev_ctx, "ata"); // Initialize the BGA driver. - BGA::Init(); + RunDriverThread(BGAThread, NULL, "bga"); // Initialize the filesystem network. NetFS::Init(); @@ -644,9 +711,15 @@ static void BootThread(void* /*user*/) { // Initialize the EM driver. if ( enable_em ) - EM::Init("/dev", slashdev); + RunDriverThread(EMThread, &dev_ctx, "em"); } + // Await the drivers initialized in the background threads. + kthread_mutex_lock(&driver_threads_lock); + while ( driver_threads_done != driver_threads_total ) + kthread_cond_wait(&driver_threads_cond, &driver_threads_lock); + kthread_mutex_unlock(&driver_threads_lock); + // // Stage 6. Executing Hosted Environment ("User-Space") //