void g_idt::load() { // Load the IDT g_log_debug("%! descriptor table lays at %h", "idt", &idt); g_log_debug("%! pointer at %h, base %h, limit %h", "idt", &idtPointer, idtPointer.base, idtPointer.limit); _loadIdt((uint32_t) & idtPointer); g_log_debug("%! loaded on core %i", "idt", g_system::currentProcessorId()); }
void g_smp::initialize(g_physical_address initialPageDirectoryPhysical) { // Write values to lower memory for use within startup code *((uint32_t*) G_CONST_SMP_STARTUP_AREA_PAGE_DIRECTORY) = initialPageDirectoryPhysical; *((uint32_t*) G_CONST_SMP_STARTUP_AREA_AP_START_ADDRESS) = (g_virtual_address) g_kernel::run_ap; *((uint32_t*) G_CONST_SMP_STARTUP_AREA_AP_COUNTER) = 0; g_log_debug("%! initial page directory for APs: %h", "smp", *((uint32_t*) G_CONST_SMP_STARTUP_AREA_PAGE_DIRECTORY)); g_log_debug("%! kernel entry point for APs: %h", "smp", *((uint32_t*) G_CONST_SMP_STARTUP_AREA_AP_START_ADDRESS)); g_log_debug("%! initial AP counter value: %i", "smp", *((uint32_t*) G_CONST_SMP_STARTUP_AREA_AP_COUNTER)); // Create enough stacks for all APs g_physical_address* stackArray = (g_physical_address*) G_CONST_SMP_STARTUP_AREA_AP_STACK_ARRAY; for (uint32_t i = 0; i < g_system::getNumberOfProcessors(); i++) { g_physical_address stackPhysical = g_pp_allocator::allocate(); if (stackPhysical == 0) { g_log_info("%*%! could not allocate physical page for AP stack", 0x0C, "smp"); return; } g_virtual_address stackVirtual = g_kernel::virtual_range_pool->allocate(1); if (stackPhysical == 0) { g_log_info("%*%! could not allocate virtual range for AP stack", 0x0C, "smp"); return; } g_address_space::map(stackVirtual, stackPhysical, DEFAULT_KERNEL_TABLE_FLAGS, DEFAULT_KERNEL_PAGE_FLAGS); g_virtual_address stackTop = (stackVirtual + G_PAGE_SIZE); stackArray[i] = stackTop; g_log_debug("%! created AP stack (%h) placed at %h", "smp", stackArray[i], &stackArray[i]); } // Copy start object from ramdisk to lower memory const char* ap_startup_location = "system/lib/apstartup.o"; g_ramdisk_entry* startupObject = g_kernel::ramdisk->findAbsolute(ap_startup_location); if (startupObject == 0) { g_log_info("%*%! could not initialize due to missing apstartup object at '%s'", 0x0C, "smp", ap_startup_location); return; } g_memory::copy((uint8_t*) G_CONST_SMP_STARTUP_AREA_CODE_START, (uint8_t*) startupObject->data, startupObject->datalength); // Start APs g_processor* n = g_system::getProcessorList(); while (n) { if (!n->bsp) { initialize_core(n); } n = n->next; } }
void g_kernel::print_header(g_setup_information* info) { // Print header g_console_video::clear(); g_log_infon(""); g_log_infon(""); g_log_infon(""); g_console_video::setColor(0x90); g_log_infon("Ghost Kernel"); g_console_video::setColor(0x0F); g_log_info(" Version %i.%i.%i", G_VERSION_MAJOR, G_VERSION_MINOR, G_VERSION_PATCH); g_log_info(""); g_log_info(" Copyright (C) 2014, Max Schluessel <*****@*****.**>"); g_log_info(""); g_log_info("%! loading", "prekern"); // Print setup information g_log_debug("%! setup information:", "prekern"); g_log_debug("%# reserved: %h - %h", info->kernelImageStart, info->kernelImageEnd); g_log_debug("%# stack: %h - %h", info->stackStart, info->stackEnd); g_log_debug("%# bitmap: %h - %h", info->bitmapStart, info->bitmapEnd); g_log_debug("%# heap: %h - %h", info->heapStart, info->heapEnd); g_log_debug("%# mbstruct: %h", info->multibootInformation); g_log_debug("%! started", "kern"); g_log_debug("%! got setup information at %h", "kern", info); }
void g_lapic::startTimer() { g_log_debug("%! starting timer", "lapic"); // Tell APIC timer to use divider 16 write(APIC_REGISTER_TIMER_DIV, 0x3); // Prepare the PIT to sleep for 10ms (10000µs) g_pit::prepareSleep(10000); // Set APIC init counter to -1 write(APIC_REGISTER_TIMER_INITCNT, 0xFFFFFFFF); // Perform PIT-supported sleep g_pit::performSleep(); // Stop the APIC timer write(APIC_REGISTER_LVT_TIMER, APIC_LVT_INT_MASKED); // Now we know how often the APIC timer has ticked in 10ms uint32_t ticksPer10ms = 0xFFFFFFFF - read(APIC_REGISTER_TIMER_CURRCNT); // Start timer as periodic on IRQ 0 write(APIC_REGISTER_LVT_TIMER, 32 | APIC_LVT_TIMER_MODE_PERIODIC); write(APIC_REGISTER_TIMER_DIV, 0x3); write(APIC_REGISTER_TIMER_INITCNT, ticksPer10ms); }
void g_pipes::remove_reference(g_pipe_id id, g_pid pid) { auto pipe_entry = pipes->get(id); if (pipe_entry) { g_pipe* pipe = pipe_entry->value; // find entry and remove g_list_entry<g_pid>* prev = 0; g_list_entry<g_pid>* entry = pipe->references; while (entry) { if (entry->value == pid) { if (prev == 0) { pipe->references = entry->next; } else { prev->next = entry->next; } delete entry; break; } prev = entry; entry = entry->next; } // no entry left? if (pipe->references == 0) { pipes->remove(id); g_log_debug("%! removing non-referenced pipe %i", "pipes", id); delete pipe->buffer; delete pipe; } } }
void g_scheduler::add(g_thread* t) { model_lock.lock(); // set the scheduler on the task t->scheduler = this; // the idle task is not added to a queue if (t->priority == g_thread_priority::IDLE) { g_task_entry* entry = new g_task_entry; entry->value = t; entry->next = 0; idle_entry = entry; } else { // add task to run queue g_task_entry* entry = new g_task_entry; entry->value = t; entry->next = run_queue; run_queue = entry; } g_log_debug("%! task %i assigned to core %i", "scheduler", t->id, coreId); model_lock.unlock(); }
bool g_scheduler::killAllThreadsOf(g_process* process) { bool living_threads_remain = false; model_lock.lock(); // set all threads in run queue to dead auto entry = run_queue; while (entry) { if ((entry->value->process->main->id == process->main->id) && entry->value->alive) { entry->value->alive = false; living_threads_remain = true; } entry = entry->next; } // set all threads in wait queue to dead entry = wait_queue; while (entry) { if ((entry->value->process->main->id == process->main->id) && entry->value->alive) { entry->value->alive = false; living_threads_remain = true; } entry = entry->next; } g_log_debug("%! waiting for all threads of process %i to exit: %s", "scheduler", current_entry->value->id, (living_threads_remain ? "still waiting" : "all finished")); model_lock.unlock(); return living_threads_remain; }
void g_scheduler::printWaiterDeadlockWarning() { char* taskName = (char*) "?"; if (current_entry->value->getIdentifier() != 0) { taskName = (char*) current_entry->value->getIdentifier(); } g_log_debug("%! thread %i (process %i, named '%s') waits for '%s'", "deadlock-detector", current_entry->value->id, current_entry->value->process->main->id, taskName, current_entry->value->waitManager->debug_name()); }
void g_filesystem::process_forked(g_pid source, g_pid fork) { g_file_descriptor_table* source_table = g_file_descriptors::get_process_table(source); // clone each entry for (auto iter = source_table->descriptors.begin(); iter != source_table->descriptors.end(); ++iter) { g_file_descriptor_content* content = iter->value; g_fs_clonefd_status stat; clonefd(content->id, source, content->id, fork, &stat); g_log_debug("%! forking cloned fd %i from process %i -> %i with status %i", "filesystem", content->id, source, fork, stat); } }
void g_scheduler::add(g_thread* t) { lock(); g_list_entry<g_thread*>* entry = new g_list_entry<g_thread*>; entry->value = t; entry->next = taskList; taskList = entry; g_log_debug("%! task %i assigned to core %i", "scheduler", t->id, coreId); unlock(); }
/** * Spawns a ramdisk file as a process. */ g_elf32_spawn_status g_elf32_loader::spawnFromRamdisk(g_ramdisk_entry* entry, g_security_level securityLevel, g_thread** target, const char* arguments, bool enforceCurrentCore) { // Check file if (entry == 0 || entry->type != G_RAMDISK_ENTRY_TYPE_FILE) { return ELF32_SPAWN_STATUS_FILE_NOT_FOUND; } // Get and validate ELF header elf32_ehdr* header = (elf32_ehdr*) entry->data; g_elf32_validation_status status = validate(header); if (status == ELF32_VALIDATION_SUCCESSFUL) { // Create the process g_thread* mainThread = g_thread_manager::createProcess(securityLevel); if (mainThread == 0) { g_log_warn("%! failed to create main thread to spawn ELF binary from ramdisk", "elf32"); return ELF32_SPAWN_STATUS_PROCESS_CREATION_FAILED; } g_process* process = mainThread->process; // Temporarily switch to the new processes page directory to load the binary to it g_page_directory thisPageDirectory = g_address_space::get_current_space(); g_address_space::switch_to_space(process->pageDirectory); loadBinaryToCurrentAddressSpace(header, process); g_thread_manager::prepare_thread_local_storage(mainThread); g_address_space::switch_to_space(thisPageDirectory); // Set the tasks entry point mainThread->cpuState->eip = header->e_entry; // Give CLI if (arguments) { process->cliArguments = new char[G_CLIARGS_BUFFER_LENGTH]; uint32_t argsLen = g_string::length(arguments); g_memory::copy(process->cliArguments, arguments, argsLen); process->cliArguments[argsLen] = 0; g_log_debug("%! kernel stored cli arguments for task %i", "elf32", process->main->id); } // Add to scheduling list g_tasking::addTask(mainThread, enforceCurrentCore); // Set out parameter *target = mainThread; return ELF32_SPAWN_STATUS_SUCCESSFUL; } return ELF32_SPAWN_STATUS_VALIDATION_ERROR; }
void g_lapic::prepare(g_physical_address lapicAddress) { physicalBase = lapicAddress; prepared = true; // Warn if APIC not at expected location if (physicalBase != G_EXPECTED_APIC_PHYSICAL_ADDRESS) { g_log_warn("%! is at %h, not %h as expected", "lapic", physicalBase, G_EXPECTED_APIC_PHYSICAL_ADDRESS); } g_log_debug("%! base is %h", "lapic", physicalBase); // Map it to virtual space createMapping(); }
void g_filesystem::process_closed(g_pid pid) { g_file_descriptor_table* table = g_file_descriptors::get_process_table(pid); // close each entry for (auto iter = table->descriptors.begin(); iter != table->descriptors.end(); ++iter) { g_file_descriptor_content* content = iter->value; auto node_entry = nodes->get(content->node_id); if (node_entry) { g_fs_close_status stat; close(pid, node_entry->value, content, &stat); if (stat == G_FS_CLOSE_SUCCESSFUL) { g_log_debug("%! successfully closed fd %i when exiting process %i", "filesystem", content->id, pid); } else { g_log_debug("%! failed to close fd %i when exiting process %i with status %i", "filesystem", content->id, pid, stat); } } } // remove all entries g_file_descriptors::unmap_all(pid); }
void g_kernel::run(g_setup_information* info) { // perform initial setup pre_setup(info); // copy remaining information from loader information g_physical_address initial_pd_physical = info->initialPageDirectoryPhysical; g_log_debug("%! unmapping old address space area", "kern"); for (g_virtual_address i = G_CONST_LOWER_MEMORY_END; i < G_CONST_KERNEL_AREA_START; i += G_PAGE_SIZE) { g_address_space::unmap(i); } // NOTE: pointer to info is now invalid // run BSP setup run_bsp(initial_pd_physical); }
void g_kernel::run_ap() { ap_setup_lock.lock(); { uint32_t core = g_system::currentProcessorId(); g_log_debug("%! core %i ready for initialization", "kernap", core); // Debug ESP output uint32_t esp; asm("mov %%esp, %0":"=g"(esp)); g_log_debug("%! esp is %h", "kernap", esp); // Wait for BSP to finish setup g_log_debug("%! waiting for bsp to finish setup", "kernap"); bsp_setup_lock.lock(); g_log_debug("%! core %i got ready state from bsp", "kernap", core); bsp_setup_lock.unlock(); // Initialize GDT g_gdt_manager::initialize(); // Initialize for AP g_system::initializeAp(); // Enable tasking for this core g_tasking::enableForThisCore(); // Leave initialization load_system_process(G_IDLE_BINARY_NAME, g_thread_priority::IDLE); // tell bsp that one more is done --waiting_aps; } ap_setup_lock.unlock(); // wait for APs g_log_debug("%! waiting for %i application processors", "kernap", waiting_aps); while (waiting_aps > 0) { asm("pause"); } // Enable interrupts and wait until the first interrupt causes the scheduler to switch to the initial process g_log_debug("%! leaving initialization", "kernap"); asm("sti"); for (;;) { asm("hlt"); } }
void g_lapic::initialize() { // Read version uint32_t apicVersionRegVal = read(APIC_REGISTER_VERSION); g_log_debug("%! id %i, version %h (%s), maxlvtindex: %i", "lapic", localId, apicVersion, (apicVersion < 0x10 ? "82489DX discrete" : "integrated"), maxLvtIndex); // Initialize APIC to well-known state write(APIC_REGISTER_DEST_FORMAT, 0xFFFFFFFF); write(APIC_REGISTER_LOGICAL_DEST, (read(APIC_REGISTER_LOGICAL_DEST) & 0x00FFFFFF) | 1); write(APIC_REGISTER_LVT_TIMER, APIC_LVT_INT_MASKED); write(APIC_REGISTER_LVT_PERFMON, APIC_LVT_DELIVERY_MODE_NMI); write(APIC_REGISTER_LVT_LINT0, APIC_LVT_INT_MASKED); write(APIC_REGISTER_LVT_LINT1, APIC_LVT_INT_MASKED); write(APIC_REGISTER_TASK_PRIO, 0); // Enable the APIC write(APIC_REGISTER_SPURIOUS_IVT, 0xFF | APIC_SPURIOUS_IVT_SOFTWARE_ENABLE); // Set up timer startTimer(); }
bool g_scheduler::killAllThreadsOf(g_process* process) { bool still_has_living_threads = false; lock(); // kill all threads auto entry = taskList; while (entry) { g_thread* thr = entry->value; if (thr->process->main->id == process->main->id && thr->alive) { thr->alive = false; still_has_living_threads = true; } entry = entry->next; } g_log_debug("%! waiting for all threads of process %i to exit: %s", "scheduler", current->value->id, (still_has_living_threads ? "all finished" : "still waiting")); unlock(); return still_has_living_threads; }
void g_system::initializeBsp(g_physical_address initialPageDirectoryPhysical) { // Check if the required CPU features are available if (g_processor::supportsCpuid()) { g_log_debug("%! supports CPUID", "cpu"); } else { g_kernel::panic("%! no CPUID support", "cpu"); } // Do some CPU info output g_processor::printInformation(); // Enable SSE if available if (g_processor::hasFeature(g_cpuid_standard_edx_feature::SSE)) { g_log_info("%! support enabled", "sse"); g_processor::enableSSE(); } else { g_log_warn("%! no support detected", "sse"); } // APIC must be available if (g_processor::hasFeature(g_cpuid_standard_edx_feature::APIC)) { g_log_debug("%! APIC available", "cpu"); } else { g_kernel::panic("%! no APIC available", "cpu"); } // Gather ACPI information g_acpi::gatherInformation(); if (g_acpi::hasEntries()) { g_log_debug("%! is available", "acpi"); // Parse the MADT g_acpi_entry* cur = g_acpi::getEntryWithSignature("APIC"); if (cur) { // This creates the list of CPU's g_madt::parse(cur->header); } } else { g_kernel::panic("%! ACPI info not available", "system"); } // Initialize the interrupt controllers if (g_lapic::isPrepared() && g_ioapic_manager::areAvailable() && processor_list) { // Initialize the interrupt descriptor table g_idt::prepare(); g_idt::load(); // Disable PIC properly g_pic::remapIrqs(); g_pic::maskAll(); // Initialize local APIC g_lapic::initialize(); // Initialize each IO APIC g_ioapic* ioapic = g_ioapic_manager::getEntries(); while (ioapic) { ioapic->initialize(); ioapic = ioapic->getNext(); } // Print available CPUs g_log_info("%! %i available core%s", "system", processors_available, (processors_available > 1 ? "s" : "")); // Initialize multiprocessing g_smp::initialize(initialPageDirectoryPhysical); // Create keyboard and mouse redirection entries g_ioapic_manager::createIsaRedirectionEntry(1, 1, 0); g_ioapic_manager::createIsaRedirectionEntry(12, 12, 0); } else { g_kernel::panic("%! pic compatibility mode not implemented. apic/ioapic required!", "system"); /* PIC::remapIrqs(); PIC::unmaskAll(); */ } }
void Listener::setCustomArg( void *args ){ g_log_debug( "Setting custom argument %p for listener at %p .\n", args, this ); m_custom = args; }
net_retcode_t Listener::start(){ struct sockaddr_in servaddr; struct sockaddr_in clientaddr; int client, addrlen = sizeof(clientaddr); Socket *csocket; Thread *cthread; memset( &servaddr, 0, sizeof(servaddr) ); memset( &clientaddr, 0, addrlen ); m_sd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if( !m_sd ){ g_log_error( "Could not create listener socket ([%d] %s).\n", errno, strerror(errno) ); return NET_FAILED; } servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(m_port); int opt = 1; if( setsockopt( m_sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt) ) == -1 ){ g_log_error( "Could not set SO_REUSEADDR option ([%d] %s).\n", errno, strerror(errno) ); return NET_FAILED; } // prevents broken pipe error during acccept if( setsockopt( m_sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt) ) == -1 ){ g_log_error( "Could not set SO_NOSIGPIPE option ([%d] %s).\n", errno, strerror(errno) ); return NET_FAILED; } if( bind( m_sd, (sockaddr *)&servaddr, sizeof(servaddr) ) == -1 ){ g_log_error( "Could not bind listener ([%d] %s).\n", errno, strerror(errno) ); return NET_FAILED; } if( listen( m_sd, m_backlog ) == -1 ){ g_log_error( "Could not start listener ([%d] %s).\n", errno, strerror(errno) ); return NET_FAILED; } while( 1 ){ if( (client = accept( m_sd, (sockaddr *)&clientaddr, (socklen_t *)&addrlen )) != -1 ){ csocket = new Socket(client); cthread = new Thread(m_acceptor); csocket->setAddress( clientaddr.sin_addr.s_addr ); csocket->setNonBlocking(); g_log_info( "Accepted new connection from %s .\n", csocket->getAddress() ); if( m_custom == NULL ){ cthread->start( csocket ); } else{ g_listener_custom_args_t *args = (g_listener_custom_args_t *)calloc( 1, sizeof(g_listener_custom_args_t) ); args->client = csocket; args->custom = m_custom; cthread->start( args ); } g_log_debug( "Client acceptor started .\n" ); } else{ g_log_warning( "Error while accepting incoming connection ([%d] %s).\n", errno, strerror(errno) ); } } return NET_OK; }
void g_loader::initialize(g_multiboot_information* multibootInformation) { // Store multiboot structure setupInformation.multibootInformation = multibootInformation; // Begin initialization g_log_info("%! loader initializing", "loader"); // End of the loader binary in memory uint32_t loaderEndAddress = PAGE_ALIGN_UP((uint32_t ) &endAddress); // Find free spaces to place the GDT and the bitmap uint32_t gdtAreaStart = findFreeMemory(multibootInformation, loaderEndAddress, 1); uint32_t gdtAreaEnd = gdtAreaStart + G_PAGE_SIZE; uint32_t bitmapStart = findFreeMemory(multibootInformation, gdtAreaEnd, PAGE_ALIGN_UP(G_BITMAP_SIZE) / G_PAGE_SIZE); uint32_t bitmapEnd = PAGE_ALIGN_UP(bitmapStart + G_BITMAP_SIZE); // The "reservedAreaEnd" is the end of the memory (somewhere above 1MiB) // that is not occupied by the loader binary or the pages that we split // of for use as bitmap and GDT. uint32_t reservedAreaEnd = bitmapEnd; #if G_LOGGING_DEBUG // Information output g_log_debug("%! available modules:", "mmodule"); for (uint32_t i = 0; i < multibootInformation->modulesCount; i++) { g_multiboot_module* module = (g_multiboot_module*) (multibootInformation->modulesAddress + sizeof(g_multiboot_module) * i); g_log_debug("%# '%s' at %h - %h", module->path, module->moduleStart, module->moduleEnd); } g_log_debug("%! calculated addresses:", "loader"); g_log_debug("%# gdt area: %h", gdtAreaStart); g_log_debug("%# bitmap: %h", bitmapStart); g_log_debug("%# reserved area end: %h", reservedAreaEnd); #endif // Store setup information setupInformation.bitmapStart = bitmapStart; setupInformation.bitmapEnd = bitmapEnd; // Set up the GDT. Here we pass the address of the gdt area, which contains enough space to // create the descriptor table and its pointer. g_gdt_manager::initialize(gdtAreaStart); // Read GRUB map to add free pages to the allocator physicalAllocator.initialize((g_bitmap_entry*) bitmapStart); g_multiboot_mmap_interpreter::load(&physicalAllocator, reservedAreaEnd); // Set up paging, this relocates the multiboot modules g_paging_initializer::initialize(reservedAreaEnd, &setupInformation); // IMPORTANT: Now the multiboot module location has changed! // Load kernel binary g_log_info("%! locating kernel binary...", "loader"); g_multiboot_module* kernelModule = g_multiboot_util::findModule(setupInformation.multibootInformation, "/boot/kernel"); if (kernelModule) { g_log_info("%! found kernel binary at %h, loading...", "loader", kernelModule->moduleStart); g_kernel_loader::load(kernelModule); g_loader::panic("%! something went wrong during boot process, halting", "loader"); } else { g_loader::panic("%! kernel module not found", "loader"); } }