📄 kernelmultitasker.c
字号:
//// Visopsys// Copyright (C) 1998-2005 J. Andrew McLaughlin// // This program is free software; you can redistribute it and/or modify it// under the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 of the License, or (at your option)// any later version.// // This program is distributed in the hope that it will be useful, but// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License// for more details.// // You should have received a copy of the GNU General Public License along// with this program; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.//// kernelMultitasker.c//// This file contains the C functions belonging to the kernel's // multitasker#include "kernelMultitasker.h"#include "kernelParameters.h"#include "kernelMemory.h"#include "kernelMalloc.h"#include "kernelFile.h"#include "kernelMain.h"#include "kernelPage.h"#include "kernelProcessorX86.h"#include "kernelPic.h"#include "kernelSysTimer.h"#include "kernelEnvironment.h"#include "kernelShutdown.h"#include "kernelMisc.h"#include "kernelInterrupt.h"#include "kernelNetwork.h"#include "kernelLog.h"#include "kernelError.h"#include <stdio.h>#include <string.h>#include <signal.h>#define PROC_KILLABLE(proc) ((proc != kernelProc) && \ (proc != idleProc) && \ (proc != kernelCurrentProcess))// next added for I/O port protection by Davide Airaghi#define SET_PORT_BIT(port,portarr) portarr[ port / 8 ] |= 1 << (port % 8);#define UNSET_PORT_BIT(port,portarr) portarr[ port / 8 ] &= ~(1 << (port %8));#define GET_PORT_BIT(port,portarr) (portarr[ port / 8] >> (port % 8)) & 0x01;#define ALLOW_PORT_IO(port,portarr) UNSET_PORT_BIT(port,portarr)#define NOT_ALLOW_PORT_IO(port,portarr) SET_PORT_BIT(port,portarr)#define FILL_PORT_BYTES(cont,portarr,val) for (cont=0;cont<PORTS_BYTES;cont++) portarr[cont]=val;#define IOMAP_REQUESTED_SIZE(max_port) (((max_port / 8)*8)+1) // Global multitasker stuffstatic int multitaskingEnabled = 0;static volatile int processIdCounter = KERNELPROCID;static kernelProcess *kernelProc = NULL;static kernelProcess *idleProc = NULL;static volatile int schedulerSwitchedByCall = 0;static int fpuProcess = 0;// We allow the pointer to the current process to be exported, so that// when a process uses system calls, there is an easy way for the// process to get information about itself.kernelProcess *kernelCurrentProcess = NULL;// Process queue for CPU executionstatic kernelProcess* processQueue[MAX_PROCESSES];static volatile int numQueued = 0;// Things specific to the scheduler. The scheduler process is just a// convenient place to keep things, we don't use all of it and it doesn't// go in the queuestatic kernelProcess *schedulerProc = NULL;static volatile int schedulerStop = 0;static void (*oldSysTimerHandler)(void) = NULL;static volatile unsigned schedulerTimeslices = 0;static volatile unsigned schedulerTime = 0;// An array of exception types. The selectors are initialized later.struct { int index; kernelSelector tssSelector; const char *a; const char *name; int (*handler) (void);} exceptionVector[19] = { { EXCEPTION_DIVBYZERO, 0, "a", "divide-by-zero", NULL }, { EXCEPTION_DEBUG, 0, "a", "debug", NULL }, { EXCEPTION_NMI, 0, "a", "non-maskable interrupt (NMI)", NULL }, { EXCEPTION_BREAK, 0, "a", "breakpoint", NULL }, { EXCEPTION_OVERFLOW, 0, "a", "overflow", NULL }, { EXCEPTION_BOUNDS, 0, "a", "out-of-bounds", NULL }, { EXCEPTION_OPCODE, 0, "an", "invalid opcode", NULL }, { EXCEPTION_DEVNOTAVAIL, 0, "a", "device not available", NULL }, { EXCEPTION_DOUBLEFAULT, 0, "a", "double-fault", NULL }, { EXCEPTION_COPROCOVER, 0, "a", "co-processor segment overrun", NULL }, { EXCEPTION_INVALIDTSS, 0, "an", "invalid TSS", NULL }, { EXCEPTION_SEGNOTPRES, 0, "a", "segment not present", NULL }, { EXCEPTION_STACK, 0, "a", "stack", NULL }, { EXCEPTION_GENPROTECT, 0, "a", "general protection", NULL }, { EXCEPTION_PAGE, 0, "a", "page fault", NULL }, { EXCEPTION_RESERVED, 0, "a", "\"reserved\"", NULL }, { EXCEPTION_FLOAT, 0, "a", "floating point", NULL }, { EXCEPTION_ALIGNCHECK, 0, "an", "alignment check", NULL }, { EXCEPTION_MACHCHECK, 0, "a", "machine check", NULL }};static kernelProcess *getProcessById(int processId){ // This routine is used to find a process' pointer based on the process // Id. Nothing fancy -- it just searches through the list. Maybe later // it can be some kind of fancy sorting/searching procedure. Returns NULL // if the process doesn't exist kernelProcess *theProcess = NULL; int count; for (count = 0; count < numQueued; count ++) if (processQueue[count]->processId == processId) { theProcess = processQueue[count]; break; } // If we didn't find it, this will still be NULL return (theProcess);}static kernelProcess *getProcessByName(const char *name){ // As above, but searches by name kernelProcess *theProcess = NULL; int count; for (count = 0; count < numQueued; count ++) if (!strcmp((char *) processQueue[count]->processName, name)) { theProcess = processQueue[count]; break; } // If we didn't find it, this will still be NULL return (theProcess);}static inline int requestProcess(kernelProcess **processPointer){ // This routine is used to allocate new process control memory. It // should be passed a reference to a pointer that will point to // the new process, if allocated successfully. int status = 0; kernelProcess *newProcess = NULL; // Make sure the pointer->pointer parameter we were passed isn't NULL if (processPointer == NULL) // Oops. return (status = ERR_NULLPARAMETER); newProcess = kernelMalloc(sizeof(kernelProcess)); if (newProcess == NULL) return (status = ERR_MEMORY); // Success. Set the pointer for the calling process *processPointer = newProcess; return (status = 0);}// modified by Davide Airaghistatic inline int releaseProcess(kernelProcess *killProcess){ // This routine is used to free process control memory. It // should be passed the process Id of the process to kill. It // returns 0 on success, negative otherwise int status = 0; // destroy TSS data! Davide Airaghi status = kernelFree((void *) killProcess->taskStateSegment); if (status < 0) return status; status = kernelFree((void *) killProcess); return (status);}static int addProcessToQueue(kernelProcess *targetProcess){ // This routine will add a process to the task queue. It returns zero // on success, negative otherwise int status = 0; int count; if (targetProcess == NULL) // The process does not exist, or is not accessible return (status = ERR_NOSUCHPROCESS); // Make sure the priority is a legal value if ((targetProcess->priority < 0) || (targetProcess->priority > (PRIORITY_LEVELS - 1))) // The process' priority is an illegal value return (status = ERR_INVALID); // Search the process queue to make sure it isn't already present for (count = 0; count < numQueued; count ++) if (processQueue[count] == targetProcess) // Oops, it's already there return (status = ERR_ALREADY); // OK, now we can add the process to the queue processQueue[numQueued++] = targetProcess; // Done return (status = 0);}static int removeProcessFromQueue(kernelProcess *targetProcess){ // This routine will remove a process from the task queue. It returns zero // on success, negative otherwise int status = 0; int processPosition = 0; int count; if (targetProcess == NULL) // The process does not exist, or is not accessible return (status = ERR_NOSUCHPROCESS); // Search the queue for the matching process for (count = 0; count < numQueued; count ++) if (processQueue[count] == targetProcess) { processPosition = count; break; } // Make sure we found the process if (processQueue[processPosition] != targetProcess) // The process is not in the task queue return (status = ERR_NOSUCHPROCESS); // Subtract one from the number of queued processes numQueued -= 1; // OK, now we can remove the process from the queue. If there are one // or more remaining processes in this queue, we will shorten the queue // by moving the LAST process into the spot we're vacating if ((numQueued > 0) && (processPosition != numQueued)) processQueue[processPosition] = processQueue[numQueued]; // Done return (status = 0);}// modified by Davide Airaghistatic int createTaskStateSegment(kernelProcess *theProcess, void *processPageDir){ // This function will create a TSS (Task State Segment) for a new // process based on the attributes of the process. This function relies // on the privilege, userStackSize, and superStackSize attributes having // been previously set. Returns 0 on success, negative on error. int status = 0; // next vars needed by FILL_PORT_BYTES macro & other, Davide Airaghi int counter = 0; int not_for_kernel = 1; unsigned int extra_space = 0; if (theProcess->ring0 == 1) not_for_kernel = 0; // Get a free descriptor for the process' TSS status = kernelDescriptorRequest(&(theProcess->tssSelector)); if ((status < 0) || (theProcess->tssSelector == 0)) // Crap. An error getting a free descriptor. return (status); // this process belongs to admin and it's NOT part of the kernel! if (theProcess->privilege == PRIVILEGE_SUPERVISOR && not_for_kernel == 1) extra_space = sizeof(unsigned char)*(PORTS_BYTES-1); // Allocate data for TSS! Davide Airaghi theProcess->TSSsize = sizeof(kernelTSS)+extra_space; theProcess->taskStateSegment = kernelMalloc(theProcess->TSSsize); if (theProcess->taskStateSegment == NULL) { // Crap. An error getting memory! kernelDescriptorRelease(theProcess->tssSelector); return (ERR_MEMORY); } // Fill in the process' Task State Segment descriptor status = kernelDescriptorSet( theProcess->tssSelector, // TSS selector number /*&*/(theProcess->taskStateSegment), // Starts at... // removed '&' by Davide Airaghi, now this field is a pointer! theProcess->TSSsize, // Limit of a TSS segment 1, // Present in memory PRIVILEGE_SUPERVISOR, // TSSs are supervisor privilege level 0, // TSSs are system segs 0xB, // TSS, 32-bit, busy 0, // 0 for SMALL size granularity 0); // Must be 0 in TSS if (status < 0) { // Crap. An error getting a free descriptor. kernelDescriptorRelease(theProcess->tssSelector); return (status); } // Now, fill in the TSS (Task State Segment) for the new process. Parts // of this will be different depending on whether this is a user // or supervisor mode process kernelMemClear((void *) /*&*/(theProcess->taskStateSegment), theProcess->TSSsize); // removed '&' by Davide Airaghi, now this field is a pointer! // set IOBitmap's offset in TSS for I/O port protection, Davide Airaghi ((kernelTSS *)(theProcess->taskStateSegment))->IOMapBase = IOBITMAP_OFFSET; // create a pointer to IOBitmap theProcess->IOMap = (unsigned char*)(&( ((kernelTSS *)(theProcess->taskStateSegment))->IOMap)); // ok this is the kernel process! if (theProcess->privilege == PRIVILEGE_SUPERVISOR && not_for_kernel == 0) { ((kernelTSS *)(theProcess->taskStateSegment))->CS = PRIV_CODE; ((kernelTSS *)(theProcess->taskStateSegment))->DS = PRIV_DATA; ((kernelTSS *)(theProcess->taskStateSegment))->SS = PRIV_STACK; // supervisor (in this case it's the kernel or a 'part' of it) // by default can use all I/O ports he wants, Davide Airaghi // no settings required ... we're running at ring 0! } else { // cast required! Davide Airaghi ((kernelTSS *)(theProcess->taskStateSegment))->CS = USER_CODE; ((kernelTSS *)(theProcess->taskStateSegment))->DS = USER_DATA; ((kernelTSS *)(theProcess->taskStateSegment))->SS = USER_STACK; if (theProcess->privilege != PRIVILEGE_SUPERVISOR) { // normal user by default can't use any I/O port, Davide Airaghi theProcess->max_io_port = 7; // 0..7 == 1 byte ;-) theProcess->IOMap[0] = PORT_VAL_BYTE_FALSE; } else { // supervisor by default can use all I/O ports he wants, Davide Airaghi theProcess->max_io_port = IO_PORTS -1; FILL_PORT_BYTES(counter,theProcess->IOMap,PORT_VAL_BYTE_TRUE) // for debug NOT_ALLOW_PORT_IO(1111,theProcess->IOMap); } } // cast required! Davide Airaghi ((kernelTSS *)(theProcess->taskStateSegment))->ES = ((kernelTSS *)(theProcess->taskStateSegment))->DS; ((kernelTSS *)(theProcess->taskStateSegment))->FS = ((kernelTSS *)(theProcess->taskStateSegment))->DS; ((kernelTSS *)(theProcess->taskStateSegment))->GS = ((kernelTSS *)(theProcess->taskStateSegment))->DS; // cast required! Davide Airaghi ((kernelTSS *)(theProcess->taskStateSegment))->ESP = ((unsigned) theProcess->userStack + (theProcess->userStackSize - sizeof(int))); if (/*theProcess->privilege == PRIVILEGE_USER &&*/ not_for_kernel == 1) // mod by Davide Airaghi { // cast required! Davide Airaghi ((kernelTSS *)(theProcess->taskStateSegment))->SS0 = PRIV_STACK; ((kernelTSS *)(theProcess->taskStateSegment))->ESP0 = ((unsigned) theProcess->superStack + (theProcess->superStackSize - sizeof(int))); } // cast required! Davide Airaghi ((kernelTSS *)(theProcess->taskStateSegment))->EFLAGS = 0x00000202; // Interrupts enabled && IOPL = 0, // ring <= 0 can use I/O ports //0x00003202; to have IOPL == 3 ((kernelTSS *)(theProcess->taskStateSegment))->CR3 = ((unsigned) processPageDir); // All remaining values will be NULL from initialization. Note that this // includes the EIP. // Return success
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -