private void extractArguments(String[] args) { String testArgsString = Config.getString("AutoGrader.testArgs"); if (testArgsString == null) { testArgsString = ""; } for (int i = 0; i < args.length; ) { String arg = args[i++]; if (arg.length() > 0 && arg.charAt(0) == '-') { if (arg.equals("-#")) { Lib.assertTrue(i < args.length, "-# switch missing argument"); testArgsString = args[i++]; } } } StringTokenizer st = new StringTokenizer(testArgsString, ",\n\t\f\r"); while (st.hasMoreTokens()) { StringTokenizer pair = new StringTokenizer(st.nextToken(), "="); Lib.assertTrue(pair.hasMoreTokens(), "test argument missing key"); String key = pair.nextToken(); Lib.assertTrue(pair.hasMoreTokens(), "test argument missing value"); String value = pair.nextToken(); testArgs.put(key, value); } }
/** * Transfer data from the specified array to this process's virtual memory. This method handles * address translation details. This method must <i>not</i> destroy the current process if an * error occurs, but instead should return the number of bytes successfully copied (or zero if no * data could be copied). * * @param vaddr the first byte of virtual memory to write. * @param data the array containing the data to transfer. * @param offset the first byte to transfer from the array. * @param length the number of bytes to transfer from the array to virtual memory. * @return the number of bytes successfully transferred. */ public int writeVirtualMemory(int vaddr, byte[] data, int offset, int length) { Lib.assertTrue(offset >= 0 && length >= 0 && offset + length <= data.length); byte[] memory = Machine.processor().getMemory(); int transferred = 0; while (length > 0 && offset < data.length) { int addrOffset = vaddr % 1024; int virtualPage = vaddr / 1024; if (virtualPage >= pageTable.length || virtualPage < 0) { break; } TranslationEntry pte = pageTable[virtualPage]; if (!pte.valid || pte.readOnly) { break; } pte.used = true; pte.dirty = true; int physPage = pte.ppn; int physAddr = physPage * 1024 + addrOffset; int transferLength = Math.min(data.length - offset, Math.min(length, 1024 - addrOffset)); System.arraycopy(data, offset, memory, physAddr, transferLength); vaddr += transferLength; offset += transferLength; length -= transferLength; transferred += transferLength; } return transferred; }
/** * Read a null-terminated string from this process's virtual memory. Read at most <tt>maxLength + * 1</tt> bytes from the specified address, search for the null terminator, and convert it to a * <tt>java.lang.String</tt>, without including the null terminator. If no null terminator is * found, returns <tt>null</tt>. * * @param vaddr the starting virtual address of the null-terminated string. * @param maxLength the maximum number of characters in the string, not including the null * terminator. * @return the string read, or <tt>null</tt> if no null terminator was found. */ public String readVirtualMemoryString(int vaddr, int maxLength) { Lib.assertTrue(maxLength >= 0); byte[] bytes = new byte[maxLength + 1]; int bytesRead = readVirtualMemory(vaddr, bytes); for (int length = 0; length < bytesRead; length++) { if (bytes[length] == 0) return new String(bytes, 0, length); } return null; }
/** * Start this autograder. Extract the <tt>-#</tt> arguments, call <tt>init()</tt>, load and * initialize the kernel, and call <tt>run()</tt>. * * @param privilege encapsulates privileged access to the Nachos machine. */ public void start(Privilege privilege) { Lib.assertTrue(this.privilege == null, "start() called multiple times"); this.privilege = privilege; String[] args = Machine.getCommandLineArguments(); extractArguments(args); System.out.print(" grader"); init(); System.out.print("\n"); kernel = (Kernel) Lib.constructObject(Config.getString("Kernel.kernel")); kernel.initialize(args); run(); }
/** * Load the executable with the specified name into this process, and prepare to pass it the * specified arguments. Opens the executable, reads its header information, and copies sections * and arguments into this process's virtual memory. * * @param name the name of the file containing the executable. * @param args the arguments to pass to the executable. * @return <tt>true</tt> if the executable was successfully loaded. */ private boolean load(String name, String[] args) { Lib.debug(dbgProcess, "UserProcess.load(\"" + name + "\")"); OpenFile executable = ThreadedKernel.fileSystem.open(name, false); if (executable == null) { Lib.debug(dbgProcess, "\topen failed"); return false; } try { coff = new Coff(executable); } catch (EOFException e) { executable.close(); Lib.debug(dbgProcess, "\tcoff load failed"); return false; } // make sure the sections are contiguous and start at page 0 numPages = 0; for (int s = 0; s < coff.getNumSections(); s++) { CoffSection section = coff.getSection(s); if (section.getFirstVPN() != numPages) { coff.close(); Lib.debug(dbgProcess, "\tfragmented executable"); return false; } numPages += section.getLength(); } // make sure the argv array will fit in one page byte[][] argv = new byte[args.length][]; int argsSize = 0; for (int i = 0; i < args.length; i++) { argv[i] = args[i].getBytes(); // 4 bytes for argv[] pointer; then string plus one for null byte argsSize += 4 + argv[i].length + 1; } if (argsSize > pageSize) { coff.close(); Lib.debug(dbgProcess, "\targuments too long"); return false; } // program counter initially points at the program entry point initialPC = coff.getEntryPoint(); // next comes the stack; stack pointer initially points to top of it numPages += stackPages; initialSP = numPages * pageSize; // and finally reserve 1 page for arguments numPages++; if (!loadSections()) return false; // store arguments in last page int entryOffset = (numPages - 1) * pageSize; int stringOffset = entryOffset + args.length * 4; this.argc = args.length; this.argv = entryOffset; for (int i = 0; i < argv.length; i++) { byte[] stringOffsetBytes = Lib.bytesFromInt(stringOffset); Lib.assertTrue(writeVirtualMemory(entryOffset, stringOffsetBytes) == 4); entryOffset += 4; Lib.assertTrue(writeVirtualMemory(stringOffset, argv[i]) == argv[i].length); stringOffset += argv[i].length; Lib.assertTrue(writeVirtualMemory(stringOffset, new byte[] {0}) == 1); stringOffset += 1; } return true; }
private void delay() { long time = Machine.timer().getTime(); int amount = 1000; ThreadedKernel.alarm.waitUntil(amount); Lib.assertTrue(Machine.timer().getTime() >= time + amount); }
String getStringArgument(String key) { String value = (String) testArgs.get(key); Lib.assertTrue(value != null, "getStringArgument(" + key + ") failed to find key"); return value; }
/** * Request permission to receive a packet. The autograder can use this to drop packets very * selectively. * * @param privilege proves the authenticity of this call. * @return <tt>true</tt> if the packet should be delivered to the kernel. */ public boolean canReceivePacket(Privilege privilege) { Lib.assertTrue(privilege == this.privilege, "security violation"); return true; }
/** * Notify the autograder that <tt>Processor.run()</tt> was invoked. This can be used to simulate * user programs. * * @param privilege proves the authenticity of this call. */ public void runProcessor(Privilege privilege) { Lib.assertTrue(privilege == this.privilege, "security violation"); }
/** * Notify the autograder that a user program executed a syscall instruction. * * @param privilege proves the authenticity of this call. * @return <tt>true</tt> if the kernel exception handler should be called. */ public boolean exceptionHandler(Privilege privilege) { Lib.assertTrue(privilege == this.privilege, "security violation"); return true; }
/** * Notify the autograder that a timer interrupt occurred and was handled by software if a timer * interrupt handler was installed. Called by the hardware timer. * * @param privilege proves the authenticity of this call. * @param time the actual time at which the timer interrupt was issued. */ public void timerInterrupt(Privilege privilege, long time) { Lib.assertTrue(privilege == this.privilege, "security violation"); }
void level(int level) { this.level++; Lib.assertTrue(level == this.level, "level() advanced more than one step: test jumped ahead"); if (level == targetLevel) done(); }