📄 kernelmultitasker.c
字号:
kernelPageGetPhysical(newProcess->parentProcessId, execImage->code); // Make the process own its code/data memory. Don't remap it yet // because we want to map it at the requested virtual address. status = kernelMemoryChangeOwner(newProcess->parentProcessId, newProcess->processId, 0, execImage->code, NULL); if (status < 0) { // Couldn't make the process own its memory releaseProcess(newProcess); return (status); } // Remap the code/data to the requested virtual address. status = kernelPageMap(newProcess->processId, physicalCodeData, execImage->virtualAddress, execImage->imageSize); if (status < 0) { // Couldn't map the process memory releaseProcess(newProcess); return (status); } // Code should be read-only status = kernelPageSetAttrs(newProcess->processId, 0, PAGEFLAG_WRITABLE, execImage->virtualAddress, execImage->codeSize); if (status < 0) { releaseProcess(newProcess); return (status); } } else { // This process will share a page directory with its parent processPageDir = kernelPageShareDirectory(newProcess->parentProcessId, newProcess->processId); if (processPageDir == NULL) { // Not able to setup a page directory releaseProcess(newProcess); return (status = ERR_NOVIRTUAL); } } // Give the process a stack stackMemoryAddr = kernelMemoryGet((DEFAULT_STACK_SIZE + DEFAULT_SUPER_STACK_SIZE), "process stack"); if (stackMemoryAddr == NULL) { // We couldn't make a stack for the new process. Maybe the system // doesn't have anough available memory? releaseProcess(newProcess); return (status = ERR_MEMORY); } if (newProcess->privilege == PRIVILEGE_USER) { newProcess->userStackSize = DEFAULT_STACK_SIZE; newProcess->superStackSize = DEFAULT_SUPER_STACK_SIZE; } else newProcess->userStackSize = (DEFAULT_STACK_SIZE + DEFAULT_SUPER_STACK_SIZE); // Copy 'argc' and 'argv' arguments to the new process' stack while we // still own the stack memory. // Set pointers to the appropriate stack locations for the arguments args = (stackMemoryAddr + newProcess->userStackSize - (2 * sizeof(int))); // Calculate the amount of memory we need to allocate for argument data. // Leave space for pointers to the strings, since the (int argc, // char *argv[]) scheme means just 2 values on the stack: an integer // an a pointer to an array of char* pointers... argSpaceSize = ((execImage->argc + 1) * sizeof(char *)); for (count = 0; count < execImage->argc; count ++) argSpaceSize += (strlen(execImage->argv[count]) + 1); // Get memory for the argument data argSpace = kernelMemoryGet(argSpaceSize, "process arguments"); if (argSpace == NULL) { kernelMemoryRelease(stackMemoryAddr); releaseProcess(newProcess); return (status = ERR_MEMORY); } // Change ownership to the new process, and share it back with this process. if (kernelMemoryChangeOwner(newProcess->parentProcessId, newProcess->processId, 1, argSpace, (void **) &newArgAddress) < 0) { kernelMemoryRelease(stackMemoryAddr); kernelMemoryRelease(argSpace); releaseProcess(newProcess); return (status = ERR_MEMORY); } if (kernelMemoryShare(newProcess->processId, newProcess->parentProcessId, newArgAddress, (void **) &argSpace) < 0) { kernelMemoryRelease(stackMemoryAddr); releaseProcess(newProcess); return (status = ERR_MEMORY); } args[0] = execImage->argc; args[1] = (int) newArgAddress; argv = (char **) argSpace; argSpace += ((execImage->argc + 1) * sizeof(char *)); newArgAddress += ((execImage->argc + 1) * sizeof(char *)); // Copy the args into argv for (count = 0; count < execImage->argc; count ++) { strcpy((argSpace + length), execImage->argv[count]); argv[count] = (newArgAddress + length); length += (strlen(execImage->argv[count]) + 1); } // argv[argc] is supposed to be a NULL pointer, according to // some standard or other argv[args[0]] = NULL; // Unmap the argument space from this process kernelPageUnmap(newProcess->parentProcessId, argSpace, argSpaceSize); // Make the process own its stack memory status = kernelMemoryChangeOwner(newProcess->parentProcessId, newProcess->processId, 1, // remap stackMemoryAddr, (void **) &(newProcess->userStack)); if (status < 0) { // Couldn't make the process own its memory kernelMemoryRelease(stackMemoryAddr); releaseProcess(newProcess); return (status); } // Get the new virtual address of supervisor stack if (newProcess->privilege == PRIVILEGE_USER) newProcess->superStack = (newProcess->userStack + DEFAULT_STACK_SIZE); // Create the TSS (Task State Segment) for this process. status = createTaskStateSegment(newProcess, processPageDir); if (status < 0) { // Not able to create the TSS releaseProcess(newProcess); return (status); } // Adjust the stack pointer to account for the arguments that we copied to // the process' stack newProcess->taskStateSegment.ESP -= sizeof(int); // Set the EIP to the entry point newProcess->taskStateSegment.EIP = (unsigned) execImage->entryPoint; // added by Davide Airaghi for FPU-state handling FPU_STATUS_ZERO(newProcess->fpu,count) // Finally, add the process to the process queue status = addProcessToQueue(newProcess); if (status < 0) { // Not able to queue the process. releaseProcess(newProcess); return (status); } // Return the processId on success. return (status = newProcess->processId);}static int deleteProcess(kernelProcess *killProcess){ // Does all the work of actually destroyng a process when there's really // no more use for it. This occurs after all descendent threads have // terminated, for example. int status = 0; // Processes cannot delete themselves if (killProcess == kernelCurrentProcess) { kernelError(kernel_error, "Process %d cannot delete itself", killProcess->processId); return (status = ERR_INVALID); } // Remove the process from the multitasker's process queue. status = removeProcessFromQueue(killProcess); if (status < 0) { // Not able to remove the process kernelError(kernel_error, "Can't dequeue process"); return (status); } // We need to deallocate the TSS descriptor allocated to the process, if // it has one if (killProcess->tssSelector) { status = kernelDescriptorRelease(killProcess->tssSelector); // If this was unsuccessful, we don't want to continue and "lose" // the descriptor if (status < 0) { kernelError(kernel_error, "Can't release TSS"); return (status); } } // If the process has a signal stream, destroy it if (killProcess->signalStream.buffer) kernelStreamDestroy((stream *) &(killProcess->signalStream)); // Deallocate all memory owned by this process status = kernelMemoryReleaseAllByProcId(killProcess->processId); // Likewise, if this deallocation was unsuccessful, we don't want to // deallocate the process structure. If we did, the memory would become // "lost". if (status < 0) { kernelError(kernel_error, "Can't release process memory"); return (status); } // Delete the page table we created for this process status = kernelPageDeleteDirectory(killProcess->processId); // If this deletion was unsuccessful, we don't want to deallocate the // process structure. If we did, the page directory would become "lost". if (status < 0) { kernelError(kernel_error, "Can't release page directory"); return (status); } // Finally, release the process structure status = releaseProcess(killProcess); if (status < 0) { kernelError(kernel_error, "Can't release process structure"); return (status); } return (status = 0);}static int exceptionThreadInitialize(void){ // This function will initialize the kernel's exception handler thread. // It should be called after multitasking has been initialized. int status = 0; int procId = 0; int count; // One of the first things the kernel does at startup time is to install // a simple set of interrupt handlers, including ones for handling // processor exceptions. We want to replace those with a set of task // gates, so that a context switch will occur -- giving control to the // exception handler thread. // OK, we will now create the kernel's exception handler thread. procId = kernelMultitaskerSpawn(&kernelExceptionHandler, "exception thread", 0, NULL); if (procId < 0) { kernelError(kernel_error, "Unable to create the kernel's exception " "thread"); return (procId); } exceptionProc = getProcessById(procId); if (exceptionProc == NULL) { kernelError(kernel_error, "Unable to create the kernel's exception " "thread"); return (procId); } // Set the process state to sleep exceptionProc->state = proc_sleeping; status = kernelDescriptorSet( exceptionProc->tssSelector, // TSS selector &(exceptionProc->taskStateSegment), // Starts at... sizeof(kernelTSS), // Maximum size of a TSS selector 1, // Present in memory PRIVILEGE_SUPERVISOR, // Highest privilege level 0, // TSS's are system segs 0x9, // TSS, 32-bit, non-busy 0, // 0 for SMALL size granularity 0); // Must be 0 in TSS if (status < 0) // Something went wrong return (status); // Interrupts should always be disabled for this task exceptionProc->taskStateSegment.EFLAGS = 0x00000002; // Set up interrupt task gates to send all the exceptions to this new // thread for (count = 0; count < 19; count ++) { status = kernelDescriptorSetIDTTaskGate(count, exceptionProc->tssSelector); if (status < 0) { kernelError(kernel_error, "Unable to set interrupt task gate for " "exception %d", count); return (status); } } return (status = 0);}static void idleThread(void){ // This is the idle task. It runs in this loop whenever no other // processes need the CPU. However, the only thing it does inside // that loop -- as you can probably see -- is run in a loop. This should // be run at the absolute lowest possible priority so that it will not // be run unless there is absolutely nothing else in the other queues // that is ready. while(1);}static int spawnIdleThread(void){ // This function will create the idle thread at initialization time. // Returns 0 on success, negative otherwise. int status = 0; int idleProcId = 0; // The idle thread needs to be a child of the kernel idleProcId = kernelMultitaskerSpawn(idleThread, "idle thread", 0, NULL); if (idleProcId < 0) return (idleProcId); idleProc = getProcessById(idleProcId); if (idleProc == NULL) return (status = ERR_NOSUCHPROCESS); // Set it to the lowest priority status = kernelMultitaskerSetProcessPriority(idleProcId, (PRIORITY_LEVELS - 1)); if (status < 0) // There's no reason we should have to fail here, but make a warning kernelError(kernel_warn, "The multitasker was unable to lower the " "priority of the idle thread"); // Return success return (status = 0);}static int schedulerShutdown(void){ // This function will perform all of the necessary shutdown to stop // the sheduler and return control to the kernel's main task. // This will probably only be useful at system shutdown time. // NOTE that this function should NEVER be called directly. If this // advice is ignored, you have no assurance that things will occur // the way you might expect them to. To shut down the scheduler, // set the variable schedulerStop to a nonzero value. The scheduler // will then invoke this function when it's ready. int status = 0; // Restore the normal operation of the system timer 0, which is // mode 3, initial count of 0 status = kernelSysTimerSetupTimer(0, 3, 0); if (status < 0) kernelError(kernel_warn, "Could not restore system timer"); // Remove the task gate that we were using to capture the timer // interrupt. Replace it with the old default timer interrupt handler kernelInterruptHook(INTERRUPT_NUM_SYSTIMER, oldSysTimerHandler); // Give exclusive control to the current task schedulerProc->taskStateSegment.oldTSS = kernelCurrentProcess->tssSelector; // Do an interrupt return. kernelProcessorIntReturn(); // We should never get here return (status = 0);}static int markTaskBusy(int tssSelector, int busy){ // This function gets the requested TSS selector from the GDT and // marks it as busy/not busy. Returns negative on error. int status = 0; kernelDescriptor descriptor;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -