📄 kernelmultitasker.c
字号:
return (status = 0);}// modified by Davide Airaghistatic int createNewProcess(const char *name, int priority, int privilege, processImage *execImage, int newPageDir){ // This function is used to create a new process in the process // queue. It makes a "defaults" kind of process -- it sets up all of // the process' attributes with default values. If the calling process // wants something different, it should reset those attributes afterward. // If successful, it returns the processId of the new process. Otherwise, // it returns negative. int status = 0; kernelProcess *newProcess = NULL; void *stackMemoryAddr = NULL; void *processPageDir = NULL; void *physicalCodeData = NULL; int *args = NULL; char **argv = NULL; int argSpaceSize = 0; char *argSpace = NULL; char *newArgAddress = NULL; int length = 0; int count; int require_ring0 = 0; // by DAvide Airaghi if (privilege & PRIVILEGE_KERNEL || priority == KERNEL_PRIORITY) { require_ring0 = 1; privilege = privilege & ~PRIVILEGE_KERNEL; // normal user can't be at ring0!!!! if (privilege != PRIVILEGE_SUPERVISOR) require_ring0 = 0; } // for debug // kernelError(kernel_error,"%s: ring0? %d\n",name,require_ring0); // Don't bother checking the parameters, as the external functions // should have done this already. // We need to see if we can get some fresh process control memory status = requestProcess(&newProcess); if (status < 0) return (status); if (newProcess == NULL) return (status = ERR_NOFREE); // Ok, we got a new, fresh process. We need to start filling in some // of the process' data (after initializing it, of course) kernelMemClear((void *) newProcess, sizeof(kernelProcess)); // set the "ring0" field by Davide Airaghi if (require_ring0) newProcess->ring0 = 1; else newProcess->ring0 = 0; // Fill in the process' Id number newProcess->processId = processIdCounter++; // By default, the type is process newProcess->type = proc_normal; // Now, if the process Id is KERNELPROCID, then we are creating the // kernel process, and it will be its own parent. Otherwise, get the // current process and make IT be the parent of this new process if (newProcess->processId == KERNELPROCID) { newProcess->parentProcessId = newProcess->processId; newProcess->userId = 1; // root // Give it "/" as current working directory strncpy((char *) newProcess->currentDirectory, "/", 2); } else { // Make sure the current process isn't NULL if (kernelCurrentProcess == NULL) { releaseProcess(newProcess); return (status = ERR_NOSUCHPROCESS); } // Fill in the process' parent Id number newProcess->parentProcessId = kernelCurrentProcess->processId; // Fill in the process' user Id number newProcess->userId = kernelCurrentProcess->userId; // Fill in the current working directory strncpy((char *) newProcess->currentDirectory, (char *) kernelCurrentProcess->currentDirectory, MAX_PATH_LENGTH); newProcess->currentDirectory[MAX_PATH_LENGTH - 1] = '\0'; } // Fill in the process name strncpy((char *) newProcess->processName, name, MAX_PROCNAME_LENGTH); newProcess->processName[MAX_PROCNAME_LENGTH - 1] = '\0'; // Fill in the process' priority level newProcess->priority = priority; // Fill in the process' privilege level newProcess->privilege = privilege; // The amount of time since started (now) newProcess->startTime = kernelSysTimerRead(); // The thread's initial state will be "stopped" newProcess->state = proc_stopped; // Do we need to create a new page directory and a set of page tables for // this process? if (newPageDir) { // We need to make a new page directory, etc. processPageDir = kernelPageNewDirectory(newProcess->processId, newProcess->privilege); if (processPageDir == NULL) { // Not able to setup a page directory releaseProcess(newProcess); return (status = ERR_NOVIRTUAL); } // Get the physical address of the code/data physicalCodeData = 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 (!require_ring0) // (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 (!require_ring0) // (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 // cast required! Davide Airaghi ((kernelTSS *)(newProcess->taskStateSegment))->ESP -= sizeof(int); // Set the EIP to the entry point // cast required! Davide Airaghi ((kernelTSS *)(newProcess->taskStateSegment))->EIP = (unsigned) execImage->entryPoint; // 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); } } // Try to close all network connections owned by this process status = kernelNetworkCloseAll(killProcess->processId); if (status < 0) kernelError(kernel_warn, "Can't release network connections"); // 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 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -