// exception.cc // Entry point into the Nachos kernel from user programs. // There are two kinds of things that can cause control to // transfer back to here from user code: // // syscall -- The user code explicitly requests to call a procedure // in the Nachos kernel. Right now, the only function we support is // "Halt". // // exceptions -- The user code does something that the CPU can't handle. // For instance, accessing memory that doesn't exist, arithmetic errors, // etc. // // Interrupts (which can also cause control to transfer from user // code into the Nachos kernel) are handled elsewhere. // // For now, this only handles the Halt() system call. // Everything else core dumps. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #include "copyright.h" #include "system.h" #include "syscall.h" //---------------------------------------------------------------------- // ExceptionHandler // Entry point into the Nachos kernel. Called when a user program // is executing, and either does a syscall, or generates an addressing // or arithmetic exception. // // For system calls, the following is the calling convention: // // system call code -- r2 // arg1 -- r4 // arg2 -- r5 // arg3 -- r6 // arg4 -- r7 // // The result of the system call, if any, must be put back into r2. // // And don't forget to increment the pc before returning. (Or else you'll // loop making the same system call forever! // // "which" is the kind of exception. The list of possible exceptions // are in machine.h. //---------------------------------------------------------------------- #include "system.h" #include "syscall.h" #include "process.h" #include "console.h" #include "synch.h" Lock* proLock = new Lock("process lock"); Lock* conLock = new Lock("process lock"); void RunProcess(int dummy){ currentThread->space->InitRegisters(); currentThread->space->RestoreState(); machine->Run(); } void AdvancePC(){ int pc; pc = machine->ReadRegister(PCReg); machine->WriteRegister(PrevPCReg, pc); pc = machine->ReadRegister(NextPCReg); machine->WriteRegister(PCReg, pc); pc += 4; machine->WriteRegister(NextPCReg, pc); } void ExceptionHandler(ExceptionType which) { int type = machine->ReadRegister(2); if((which==SyscallException)){ int arg1 = machine->ReadRegister(4); int arg2 = machine->ReadRegister(5); int arg3 = machine->ReadRegister(6); OpenFile* oFile = NULL; Thread* processThread = NULL; int i = 0; bool flag = true; Process* newProcess; char* name; int index; int size; int value; int temp; char chr; char* proArgs; //For SC_Join Process* waitingProc; Process* joinableProc; switch(type) { case SC_Halt: DEBUG('a', "Shutdown, initiated by user program.\n"); interrupt->Halt(); break; case SC_Exit: DEBUG('a', "SYSCALL: Exiting program!!! Status=%d",arg1); (currentThread->getProcess())->processFinish(); currentThread->Finish(); break; case SC_Exec: DEBUG('a', "SYSCALL: Exec Name"); name = new char[256]; proArgs = new char[256]; flag = true; i = 0; while(flag) { if(machine->ReadMem(arg1, 1, &temp)) { name[i] = (char)temp; if ((char)temp == '\0') flag = false; arg1++; i++; } } oFile= fileSystem->Open(name); if (oFile == NULL) { printf("Unable to open file %s\n", name); break; } proLock->Acquire(); processThread = new Thread("new process"); newProcess = new Process(oFile); if(arg2 !=0){ flag = true; i = 0; while(flag) { if(machine->ReadMem(arg2, 1, &temp)) { newProcess->argBuffer[i] = (char)temp; if ((char)temp == '\0') flag = false; arg2++; i++; } } } else{ newProcess->argBuffer[0] = '\0'; } processThread->setProcess(newProcess); processThread->space = newProcess->getSpace(); machine->WriteRegister(2,newProcess->getPID()); processThread->Fork(&RunProcess, 1); proLock->Release(); delete oFile; delete name; name = NULL; break; case SC_Join: DEBUG('a', "SYSCALL: Join!!! Id=%d"); // arg1 contains Process ID joinableProc = processMap.lookup(arg1); if(joinableProc == NULL || joinableProc == waitingProc) { machine->WriteRegister(2, -1); break; } waitingProc = currentThread->getProcess(); joinableProc->Join(currentThread); break; case SC_Create: name = new char[256]; DEBUG('a', "SYSCALL: Create!!!\n"); flag = true; i = 0; while(flag) { if(machine->ReadMem(arg1, 1, &temp)) { name[i] = (char)temp; if ((char)temp == '\0') flag = false; arg1++; i++; } } fileSystem->Create(name,0); delete name; name = NULL; break; case SC_Open: DEBUG('a', "SYSCALL: Open!!!\n"); name = new char[256]; flag = true; i = 0; while(flag) { if(machine->ReadMem(arg1, 1, &temp)) { name[i] = (char)temp; if ((char)temp == '\0') flag = false; arg1++; i++; } } oFile = fileSystem->Open(name); if(oFile == NULL){ printf("unable to open file %s, try creating %s first \n", name, name); machine->WriteRegister(2, -1); break; } flag = false; for(i = 2; i<10 && !flag; i++){ if((currentThread->getProcess())->openFileTable[i] ==NULL){ (currentThread->getProcess())->openFileTable[i] = oFile; flag = true; } } if(flag){ machine->WriteRegister(2, i-1); } else{ printf("open file limit exceeded\n"); machine->WriteRegister(2, -1); break; } delete name; name = NULL; break; case SC_Read: DEBUG('a', "SYSCALL: Read!!!\n"); name = new char[256]; index = arg3; size = arg2; if(index >1 && index <10){ oFile = (currentThread->getProcess())->openFileTable[index]; value = oFile->Read(name, size); } else if(index == 0){ i = 0; conLock->Acquire(); do{ readA->P(); chr = consoleStd->GetChar(); if(chr != '\n'){ name[i] = chr; } else{ name[i] = '\0'; } i++; } while(iRelease(); } else{ printf("unrecognized file!!!\n"); machine->WriteRegister(2,-1); delete name; name = NULL; break; } i = 0; while(i < value) { temp = (int)name[i]; machine->WriteMem(arg1, 1, temp); arg1++; i++; } machine->WriteRegister(2,value); delete name; name = NULL; break; case SC_Write: DEBUG('a', "SYSCALL: Write!!!\n"); name = new char[256]; flag = true; i = 0; while(flag) { if(machine->ReadMem(arg1, 1, &temp)) { name[i] = (char)temp; if ((char)temp == '\0') flag = false; arg1++; i++; } } index = arg3; size = arg2; if(index >1 && index <10){ oFile = (currentThread->getProcess())->openFileTable[index]; value = oFile->Write(name, size); } else if(index ==1){ conLock->Acquire(); i = 0; while(i < size){ consoleStd->PutChar(name[i]); writeD->P(); i++; } conLock->Release(); } else{ printf("unrecognized file!!!!\n"); machine->WriteRegister(2,-1); delete name; name = NULL; break; } machine->WriteRegister(2,value); delete name; name = NULL; break; case SC_Close: DEBUG('a', "SYSCALL: Close!!!\n"); index = arg1; if(index <2){ printf("cannot close console\n"); break; } if(index > 10){ printf("invalid file id\n"); break; } if((currentThread->getProcess())->openFileTable[index] !=NULL){ delete (currentThread->getProcess())->openFileTable[index]; (currentThread->getProcess())->openFileTable[index] = NULL; } else{ printf("File is already closed\n"); machine->WriteRegister(2,-1); break; } break; case SC_Fork: DEBUG('a', "SYSCALL: Fork. Not implemented yet!!!\n"); break; case SC_Yield: DEBUG('a', "SYSCALL: Yield. Not Implemeted yet!!!\n"); break; case SC_GetArgs: DEBUG('a', "SYSCALL: GetArgs.\n"); i = 0; while((char)temp != '\0') { temp = (int)((currentThread->getProcess())->argBuffer[i]); machine->WriteMem(arg1, 1, temp); arg1++; i++; } break; default: printf("Unexpected system call type exception %d %d\n", which, type); break; //ASSERT(FALSE); } } else{ printf("Unexpected user mode exception %d %d\n", which, type); } AdvancePC(); }