490 lines
16 KiB
Java
490 lines
16 KiB
Java
// PART OF THE MACHINE SIMULATION. DO NOT CHANGE.
|
|
|
|
package nachos.machine;
|
|
|
|
import nachos.security.*;
|
|
import nachos.ag.*;
|
|
|
|
import java.io.File;
|
|
|
|
/**
|
|
* The master class of the simulated machine. Processes command line arguments,
|
|
* constructs all simulated hardware devices, and starts the grader.
|
|
*/
|
|
public final class Machine {
|
|
/**
|
|
* Nachos main entry point.
|
|
*
|
|
* @param args the command line arguments.
|
|
*/
|
|
public static void main(final String[] args) {
|
|
System.out.print("nachos 5.0j initializing...");
|
|
|
|
Lib.assertTrue(Machine.args == null);
|
|
Machine.args = args;
|
|
|
|
processArgs();
|
|
|
|
Config.load(configFileName);
|
|
|
|
// get the current directory (.)
|
|
baseDirectory = new File(new File("").getAbsolutePath());
|
|
// get the nachos directory (./nachos)
|
|
nachosDirectory = new File(baseDirectory, "nachos");
|
|
|
|
String testDirectoryName =
|
|
Config.getString("FileSystem.testDirectory");
|
|
|
|
// get the test directory
|
|
if (testDirectoryName != null) {
|
|
testDirectory = new File(testDirectoryName);
|
|
}
|
|
else {
|
|
// use ../test
|
|
testDirectory = new File(baseDirectory.getParentFile(), "test");
|
|
}
|
|
|
|
securityManager = new NachosSecurityManager(testDirectory);
|
|
privilege = securityManager.getPrivilege();
|
|
|
|
privilege.machine = new MachinePrivilege();
|
|
|
|
TCB.givePrivilege(privilege);
|
|
privilege.stats = stats;
|
|
|
|
securityManager.enable();
|
|
createDevices();
|
|
checkUserClasses();
|
|
|
|
autoGrader = (AutoGrader) Lib.constructObject(autoGraderClassName);
|
|
|
|
new TCB().start(new Runnable() {
|
|
public void run() { autoGrader.start(privilege); }
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Yield to non-Nachos threads. Use in non-preemptive JVM's to give
|
|
* non-Nachos threads a chance to run.
|
|
*/
|
|
public static void yield() {
|
|
Thread.yield();
|
|
}
|
|
|
|
/**
|
|
* Terminate Nachos. Same as <tt>TCB.die()</tt>.
|
|
*/
|
|
public static void terminate() {
|
|
TCB.die();
|
|
}
|
|
|
|
/**
|
|
* Terminate Nachos as the result of an unhandled exception or error.
|
|
*
|
|
* @param e the exception or error.
|
|
*/
|
|
public static void terminate(Throwable e) {
|
|
if (e instanceof ThreadDeath)
|
|
throw (ThreadDeath) e;
|
|
|
|
e.printStackTrace();
|
|
terminate();
|
|
}
|
|
|
|
/**
|
|
* Print stats, and terminate Nachos.
|
|
*/
|
|
public static void halt() {
|
|
System.out.print("Machine halting!\n\n");
|
|
stats.print();
|
|
terminate();
|
|
}
|
|
|
|
/**
|
|
* Return an array containing all command line arguments.
|
|
*
|
|
* @return the command line arguments passed to Nachos.
|
|
*/
|
|
public static String[] getCommandLineArguments() {
|
|
String[] result = new String[args.length];
|
|
|
|
System.arraycopy(args, 0, result, 0, args.length);
|
|
|
|
return result;
|
|
}
|
|
|
|
private static void processArgs() {
|
|
for (int i=0; i<args.length; ) {
|
|
String arg = args[i++];
|
|
if (arg.length() > 0 && arg.charAt(0) == '-') {
|
|
if (arg.equals("-d")) {
|
|
Lib.assertTrue(i < args.length, "switch without argument");
|
|
Lib.enableDebugFlags(args[i++]);
|
|
}
|
|
else if (arg.equals("-h")) {
|
|
System.out.print(help);
|
|
System.exit(1);
|
|
}
|
|
else if (arg.equals("-m")) {
|
|
Lib.assertTrue(i < args.length, "switch without argument");
|
|
try {
|
|
numPhysPages = Integer.parseInt(args[i++]);
|
|
}
|
|
catch (NumberFormatException e) {
|
|
Lib.assertNotReached("bad value for -m switch");
|
|
}
|
|
}
|
|
else if (arg.equals("-s")) {
|
|
Lib.assertTrue(i < args.length, "switch without argument");
|
|
try {
|
|
randomSeed = Long.parseLong(args[i++]);
|
|
}
|
|
catch (NumberFormatException e) {
|
|
Lib.assertNotReached("bad value for -s switch");
|
|
}
|
|
}
|
|
else if (arg.equals("-x")) {
|
|
Lib.assertTrue(i < args.length, "switch without argument");
|
|
shellProgramName = args[i++];
|
|
}
|
|
else if (arg.equals("-z")) {
|
|
System.out.print(copyright);
|
|
System.exit(1);
|
|
}
|
|
// these switches are reserved for the autograder
|
|
else if (arg.equals("-[]")) {
|
|
Lib.assertTrue(i < args.length, "switch without argument");
|
|
configFileName = args[i++];
|
|
}
|
|
else if (arg.equals("--")) {
|
|
Lib.assertTrue(i < args.length, "switch without argument");
|
|
autoGraderClassName = args[i++];
|
|
}
|
|
}
|
|
}
|
|
|
|
Lib.seedRandom(randomSeed);
|
|
}
|
|
|
|
private static void createDevices() {
|
|
interrupt = new Interrupt(privilege);
|
|
timer = new Timer(privilege);
|
|
|
|
if (Config.getBoolean("Machine.bank"))
|
|
bank = new ElevatorBank(privilege);
|
|
|
|
if (Config.getBoolean("Machine.processor")) {
|
|
if (numPhysPages == -1)
|
|
numPhysPages = Config.getInteger("Processor.numPhysPages");
|
|
processor = new Processor(privilege, numPhysPages);
|
|
}
|
|
|
|
if (Config.getBoolean("Machine.console"))
|
|
console = new StandardConsole(privilege);
|
|
|
|
if (Config.getBoolean("Machine.stubFileSystem"))
|
|
stubFileSystem = new StubFileSystem(privilege, testDirectory);
|
|
|
|
if (Config.getBoolean("Machine.networkLink"))
|
|
networkLink = new NetworkLink(privilege);
|
|
}
|
|
|
|
private static void checkUserClasses() {
|
|
System.out.print(" user-check");
|
|
|
|
Class aclsInt = (new int[0]).getClass();
|
|
Class clsObject = Lib.loadClass("java.lang.Object");
|
|
Class clsRunnable = Lib.loadClass("java.lang.Runnable");
|
|
Class clsString = Lib.loadClass("java.lang.String");
|
|
|
|
Class clsKernel = Lib.loadClass("nachos.machine.Kernel");
|
|
Class clsFileSystem = Lib.loadClass("nachos.machine.FileSystem");
|
|
Class clsRiderControls = Lib.loadClass("nachos.machine.RiderControls");
|
|
Class clsElevatorControls =
|
|
Lib.loadClass("nachos.machine.ElevatorControls");
|
|
Class clsRiderInterface =
|
|
Lib.loadClass("nachos.machine.RiderInterface");
|
|
Class clsElevatorControllerInterface =
|
|
Lib.loadClass("nachos.machine.ElevatorControllerInterface");
|
|
|
|
Class clsAlarm = Lib.loadClass("nachos.threads.Alarm");
|
|
Class clsThreadedKernel =
|
|
Lib.loadClass("nachos.threads.ThreadedKernel");
|
|
Class clsKThread = Lib.loadClass("nachos.threads.KThread");
|
|
Class clsCommunicator = Lib.loadClass("nachos.threads.Communicator");
|
|
Class clsSemaphore = Lib.loadClass("nachos.threads.Semaphore");
|
|
Class clsLock = Lib.loadClass("nachos.threads.Lock");
|
|
Class clsCondition = Lib.loadClass("nachos.threads.Condition");
|
|
Class clsCondition2 = Lib.loadClass("nachos.threads.Condition2");
|
|
Class clsRider = Lib.loadClass("nachos.threads.Rider");
|
|
Class clsElevatorController =
|
|
Lib.loadClass("nachos.threads.ElevatorController");
|
|
|
|
Lib.checkDerivation(clsThreadedKernel, clsKernel);
|
|
|
|
Lib.checkStaticField(clsThreadedKernel, "alarm", clsAlarm);
|
|
Lib.checkStaticField(clsThreadedKernel, "fileSystem", clsFileSystem);
|
|
|
|
Lib.checkMethod(clsAlarm, "waitUntil", new Class[] { long.class },
|
|
void.class);
|
|
|
|
Lib.checkConstructor(clsKThread, new Class[] { });
|
|
Lib.checkConstructor(clsKThread, new Class[] { clsRunnable });
|
|
|
|
Lib.checkStaticMethod(clsKThread, "currentThread", new Class[] {},
|
|
clsKThread);
|
|
Lib.checkStaticMethod(clsKThread, "finish", new Class[] {},
|
|
void.class);
|
|
Lib.checkStaticMethod(clsKThread, "yield", new Class[] {}, void.class);
|
|
Lib.checkStaticMethod(clsKThread, "sleep", new Class[] {}, void.class);
|
|
|
|
Lib.checkMethod(clsKThread, "setTarget", new Class[]{ clsRunnable },
|
|
clsKThread);
|
|
Lib.checkMethod(clsKThread, "setName", new Class[] { clsString },
|
|
clsKThread);
|
|
Lib.checkMethod(clsKThread, "getName", new Class[] { }, clsString);
|
|
Lib.checkMethod(clsKThread, "fork", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsKThread, "ready", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsKThread, "join", new Class[] { }, void.class);
|
|
|
|
Lib.checkField(clsKThread, "schedulingState", clsObject);
|
|
|
|
Lib.checkConstructor(clsCommunicator, new Class[] {});
|
|
Lib.checkMethod(clsCommunicator, "speak", new Class[] { int.class },
|
|
void.class);
|
|
Lib.checkMethod(clsCommunicator, "listen", new Class[] { }, int.class);
|
|
|
|
Lib.checkConstructor(clsSemaphore, new Class[] { int.class });
|
|
Lib.checkMethod(clsSemaphore, "P", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsSemaphore, "V", new Class[] { }, void.class);
|
|
|
|
Lib.checkConstructor(clsLock, new Class[] { });
|
|
Lib.checkMethod(clsLock, "acquire", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsLock, "release", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsLock, "isHeldByCurrentThread", new Class[]{ },
|
|
boolean.class);
|
|
|
|
Lib.checkConstructor(clsCondition, new Class[] { clsLock });
|
|
Lib.checkConstructor(clsCondition2, new Class[] { clsLock });
|
|
|
|
Lib.checkMethod(clsCondition, "sleep", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsCondition, "wake", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsCondition, "wakeAll", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsCondition2, "sleep", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsCondition2, "wake", new Class[] { }, void.class);
|
|
Lib.checkMethod(clsCondition2, "wakeAll", new Class[] { }, void.class);
|
|
|
|
Lib.checkDerivation(clsRider, clsRiderInterface);
|
|
|
|
Lib.checkConstructor(clsRider, new Class[] { });
|
|
Lib.checkMethod(clsRider, "initialize",
|
|
new Class[] { clsRiderControls, aclsInt }, void.class);
|
|
|
|
Lib.checkDerivation(clsElevatorController,
|
|
clsElevatorControllerInterface);
|
|
|
|
Lib.checkConstructor(clsElevatorController, new Class[] { });
|
|
Lib.checkMethod(clsElevatorController, "initialize",
|
|
new Class[] { clsElevatorControls }, void.class);
|
|
}
|
|
|
|
/**
|
|
* Prevent instantiation.
|
|
*/
|
|
private Machine() {
|
|
}
|
|
|
|
/**
|
|
* Return the hardware interrupt manager.
|
|
*
|
|
* @return the hardware interrupt manager.
|
|
*/
|
|
public static Interrupt interrupt() { return interrupt; }
|
|
|
|
/**
|
|
* Return the hardware timer.
|
|
*
|
|
* @return the hardware timer.
|
|
*/
|
|
public static Timer timer() { return timer; }
|
|
|
|
/**
|
|
* Return the hardware elevator bank.
|
|
*
|
|
* @return the hardware elevator bank, or <tt>null</tt> if it is not
|
|
* present.
|
|
*/
|
|
public static ElevatorBank bank() { return bank; }
|
|
|
|
/**
|
|
* Return the MIPS processor.
|
|
*
|
|
* @return the MIPS processor, or <tt>null</tt> if it is not present.
|
|
*/
|
|
public static Processor processor() { return processor; }
|
|
|
|
/**
|
|
* Return the hardware console.
|
|
*
|
|
* @return the hardware console, or <tt>null</tt> if it is not present.
|
|
*/
|
|
public static SerialConsole console() { return console; }
|
|
|
|
/**
|
|
* Return the stub filesystem.
|
|
*
|
|
* @return the stub file system, or <tt>null</tt> if it is not present.
|
|
*/
|
|
public static FileSystem stubFileSystem() { return stubFileSystem; }
|
|
|
|
/**
|
|
* Return the network link.
|
|
*
|
|
* @return the network link, or <tt>null</tt> if it is not present.
|
|
*/
|
|
public static NetworkLink networkLink() { return networkLink; }
|
|
|
|
/**
|
|
* Return the autograder.
|
|
*
|
|
* @return the autograder.
|
|
*/
|
|
public static AutoGrader autoGrader() { return autoGrader; }
|
|
|
|
private static Interrupt interrupt = null;
|
|
private static Timer timer = null;
|
|
private static ElevatorBank bank = null;
|
|
private static Processor processor = null;
|
|
private static SerialConsole console = null;
|
|
private static FileSystem stubFileSystem = null;
|
|
private static NetworkLink networkLink = null;
|
|
private static AutoGrader autoGrader = null;
|
|
|
|
private static String autoGraderClassName = "nachos.ag.AutoGrader";
|
|
|
|
/**
|
|
* Return the name of the shell program that a user-programming kernel
|
|
* must run. Make sure <tt>UserKernel.run()</tt> <i>always</i> uses this
|
|
* method to decide which program to run.
|
|
*
|
|
* @return the name of the shell program to run.
|
|
*/
|
|
public static String getShellProgramName() {
|
|
if (shellProgramName == null)
|
|
shellProgramName = Config.getString("Kernel.shellProgram");
|
|
|
|
Lib.assertTrue(shellProgramName != null);
|
|
return shellProgramName;
|
|
}
|
|
|
|
private static String shellProgramName = null;
|
|
|
|
/**
|
|
* Return the name of the process class that the kernel should use. In
|
|
* the multi-programming project, returns
|
|
* <tt>nachos.userprog.UserProcess</tt>. In the VM project, returns
|
|
* <tt>nachos.vm.VMProcess</tt>. In the networking project, returns
|
|
* <tt>nachos.network.NetProcess</tt>.
|
|
*
|
|
* @return the name of the process class that the kernel should use.
|
|
*
|
|
* @see nachos.userprog.UserKernel#run
|
|
* @see nachos.userprog.UserProcess
|
|
* @see nachos.vm.VMProcess
|
|
* @see nachos.network.NetProcess
|
|
*/
|
|
public static String getProcessClassName() {
|
|
if (processClassName == null)
|
|
processClassName = Config.getString("Kernel.processClassName");
|
|
|
|
Lib.assertTrue(processClassName != null);
|
|
return processClassName;
|
|
}
|
|
|
|
private static String processClassName = null;
|
|
|
|
private static NachosSecurityManager securityManager;
|
|
private static Privilege privilege;
|
|
|
|
private static String[] args = null;
|
|
|
|
private static Stats stats = new Stats();
|
|
|
|
private static int numPhysPages = -1;
|
|
private static long randomSeed = 0;
|
|
|
|
private static File baseDirectory, nachosDirectory, testDirectory;
|
|
private static String configFileName = "nachos.conf";
|
|
|
|
private static final String help =
|
|
"\n" +
|
|
"Options:\n" +
|
|
"\n" +
|
|
"\t-d <debug flags>\n" +
|
|
"\t\tEnable some debug flags, e.g. -d ti\n" +
|
|
"\n" +
|
|
"\t-h\n" +
|
|
"\t\tPrint this help message.\n" +
|
|
"\n" +
|
|
"\t-m <pages>\n" +
|
|
"\t\tSpecify how many physical pages of memory to simulate.\n" +
|
|
"\n" +
|
|
"\t-s <seed>\n" +
|
|
"\t\tSpecify the seed for the random number generator (seed is a\n" +
|
|
"\t\tlong).\n" +
|
|
"\n" +
|
|
"\t-x <program>\n" +
|
|
"\t\tSpecify a program that UserKernel.run() should execute,\n" +
|
|
"\t\tinstead of the value of the configuration variable\n" +
|
|
"\t\tKernel.shellProgram\n" +
|
|
"\n" +
|
|
"\t-z\n" +
|
|
"\t\tprint the copyright message\n" +
|
|
"\n" +
|
|
"\t-- <grader class>\n" +
|
|
"\t\tSpecify an autograder class to use, instead of\n" +
|
|
"\t\tnachos.ag.AutoGrader\n" +
|
|
"\n" +
|
|
"\t-# <grader arguments>\n" +
|
|
"\t\tSpecify the argument string to pass to the autograder.\n" +
|
|
"\n" +
|
|
"\t-[] <config file>\n" +
|
|
"\t\tSpecifiy a config file to use, instead of nachos.conf\n" +
|
|
""
|
|
;
|
|
|
|
private static final String copyright = "\n"
|
|
+ "Copyright 1992-2001 The Regents of the University of California.\n"
|
|
+ "All rights reserved.\n"
|
|
+ "\n"
|
|
+ "Permission to use, copy, modify, and distribute this software and\n"
|
|
+ "its documentation for any purpose, without fee, and without\n"
|
|
+ "written agreement is hereby granted, provided that the above\n"
|
|
+ "copyright notice and the following two paragraphs appear in all\n"
|
|
+ "copies of this software.\n"
|
|
+ "\n"
|
|
+ "IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY\n"
|
|
+ "PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL\n"
|
|
+ "DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS\n"
|
|
+ "DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN\n"
|
|
+ "ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
|
+ "\n"
|
|
+ "THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY\n"
|
|
+ "WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"
|
|
+ "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE\n"
|
|
+ "SOFTWARE PROVIDED HEREUNDER IS ON AN \"AS IS\" BASIS, AND THE\n"
|
|
+ "UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE\n"
|
|
+ "MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\n"
|
|
;
|
|
|
|
private static class MachinePrivilege
|
|
implements Privilege.MachinePrivilege {
|
|
public void setConsole(SerialConsole console) {
|
|
Machine.console = console;
|
|
}
|
|
}
|
|
|
|
// dummy variables to make javac smarter
|
|
private static Coff dummy1 = null;
|
|
}
|