public class SwapFile { public static OpenFile swapFile; private static String swapName; private static int PAGESIZE = Machine.processor().pageSize; public static List<Integer> freePages; public static List<Integer> allocatedPages; private static Lock swapLock; private static byte[] memory = Machine.processor().getMemory(); public static void initialize(String filename) { swapFile = ThreadedKernel.fileSystem.open(filename, true); swapName = filename; freePages = new LinkedList<Integer>(); allocatedPages = new LinkedList<Integer>(); swapLock = new Lock(); } public static void close() { swapFile.close(); ThreadedKernel.fileSystem.remove(swapName); } public static int insertPage(int spn, int ppn) { swapLock.acquire(); int numBits = swapFile.write(spn * PAGESIZE, memory, ppn * PAGESIZE, PAGESIZE); // assert that numBits == PAGESIZE allocatedPages.add(spn); swapLock.release(); return spn; } /* we will try to allocate a free page from the freepages*/ public static int insertPage(int ppn) { int numBits = 0; int spn = swapFile.length() / PAGESIZE; if (freePages.size() > 0) { spn = freePages.remove(0); } return insertPage(spn, ppn); } public static void readPage(int spn, int ppn) { if (allocatedPages.contains(spn)) { swapLock.acquire(); swapFile.read(spn * PAGESIZE, memory, ppn * PAGESIZE, PAGESIZE); swapLock.release(); } else { } } public static void free(int page) { swapLock.acquire(); freePages.add(page); swapLock.release(); } }
/** * Initialize this kernel. Creates a synchronized console and sets the * processor's exception handler. */ public void initialize(String[] args) { super.initialize(args); console = new SynchConsole(Machine.console()); Machine.processor().setExceptionHandler(new Runnable() { public void run() { exceptionHandler(); } }); }
private void syncTLB() { for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.valid) { pageTable[tE.vpn].dirty = tE.dirty; pageTable[tE.vpn].used = tE.used; } } }
/** * Save the state of this process in preparation for a context switch. Called by * <tt>UThread.saveState()</tt>. */ public void saveState() { for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.valid) { pageTable[tE.vpn].dirty = tE.dirty; pageTable[tE.vpn].used = tE.used; } tE.valid = false; Machine.processor().writeTLBEntry(i, tE); // savedState[i] = tE.vpn; } }
/** * The exception handler. This handler is called by the processor whenever * a user instruction causes a processor exception. * * <p> * When the exception handler is invoked, interrupts are enabled, and the * processor's cause register contains an integer identifying the cause of * the exception (see the <tt>exceptionZZZ</tt> constants in the * <tt>Processor</tt> class). If the exception involves a bad virtual * address (e.g. page fault, TLB miss, read-only, bus error, or address * error), the processor's BadVAddr register identifies the virtual address * that caused the exception. */ public void exceptionHandler() { Lib.assert(KThread.currentThread() instanceof UThread); UserProcess process = ((UThread) KThread.currentThread()).process; int cause = Machine.processor().readRegister(Processor.regCause); process.handleException(cause); }
/** * 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; }
/** Handle the halt() system call. */ private int handleHalt() { if (this.process_id != ROOT) { return 0; } Machine.halt(); Lib.assertNotReached("Machine.halt() did not halt machine!"); return 0; }
/** * Start running user programs, by creating a process and running a shell * program in it. The name of the shell program it must run is returned by * <tt>Machine.getShellProgramName()</tt>. * * @see nachos.machine.Machine#getShellProgramName */ public void run() { super.run(); UserProcess process = UserProcess.newUserProcess(); String shellProgram = Machine.getShellProgramName(); Lib.assert(process.execute(shellProgram, new String[] { })); KThread.currentThread().finish(); }
/** * Handle a user exception. Called by <tt>UserKernel.exceptionHandler()</tt> . The <i>cause</i> * argument identifies which exception occurred; see the <tt>Processor.exceptionZZZ</tt> * constants. * * @param cause the user exception that occurred. */ public void handleException(int cause) { Processor processor = Machine.processor(); switch (cause) { case Processor.exceptionTLBMiss: handleTLBMiss(); break; default: super.handleException(cause); break; } }
/** * Initialize the processor's registers in preparation for running the program loaded into this * process. Set the PC register to point at the start function, set the stack pointer register to * point at the top of the stack, set the A0 and A1 registers to argc and argv, respectively, and * initialize all other registers to 0. */ public void initRegisters() { Processor processor = Machine.processor(); // by default, everything's 0 for (int i = 0; i < processor.numUserRegisters; i++) processor.writeRegister(i, 0); // initialize PC and SP according processor.writeRegister(Processor.regPC, initialPC); processor.writeRegister(Processor.regSP, initialSP); // initialize the first two argument registers to argc and argv processor.writeRegister(Processor.regA0, argc); processor.writeRegister(Processor.regA1, argv); }
/** * Allocates memory for this process, and loads the COFF sections into memory. If this returns * successfully, the process will definitely be run (this is the last step in process * initialization that can fail). * * @return <tt>true</tt> if the sections were successfully loaded. */ protected boolean loadSections() { if (numPages > Machine.processor().getNumPhysPages()) { coff.close(); Lib.debug(dbgProcess, "\tinsufficient physical memory"); return false; } pageTable = new TranslationEntry[numPages]; for (int i = 0; i < numPages; i++) { int physPage = UserKernel.allocatePage(); if (physPage < 0) { Lib.debug(dbgProcess, "\tunable to allocate pages; tried " + numPages + ", did " + i); for (int j = 0; j < i; j++) { if (pageTable[j].valid) { UserKernel.deallocatePage(pageTable[j].ppn); pageTable[j].valid = false; } } coff.close(); return false; } pageTable[i] = new TranslationEntry(i, physPage, true, false, false, false); } // load sections for (int s = 0; s < coff.getNumSections(); s++) { CoffSection section = coff.getSection(s); Lib.debug( dbgProcess, "\tinitializing " + section.getName() + " section (" + section.getLength() + " pages)"); for (int i = 0; i < section.getLength(); i++) { int vpn = section.getFirstVPN() + i; // for now, just assume virtual addresses=physical addresses int ppn = pageTable[vpn].ppn; section.loadPage(i, ppn); if (section.isReadOnly()) { pageTable[vpn].readOnly = true; } } } coff.close(); return true; }
/** Allocate a new process. */ public UserProcess() { map = new HashMap<Integer, childProcess>(); int numPhysPages = Machine.processor().getNumPhysPages(); pageTable = new TranslationEntry[numPhysPages]; for (int i = 0; i < numPhysPages; i++) pageTable[i] = new TranslationEntry(i, i, true, false, false, false); this.process_id = unique; unique++; openfiles = new HashMap<Integer, OpenFile>(); available_descriptors = new ArrayList<Integer>(Arrays.asList(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); openfiles.put(0, UserKernel.console.openForReading()); openfiles.put(1, UserKernel.console.openForWriting()); }
/** * 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(); }
/** * Handle a user exception. Called by <tt>UserKernel.exceptionHandler()</tt>. The <i>cause</i> * argument identifies which exception occurred; see the <tt>Processor.exceptionZZZ</tt> * constants. * * @param cause the user exception that occurred. */ public void handleException(int cause) { Processor processor = Machine.processor(); switch (cause) { case Processor.exceptionSyscall: int result = handleSyscall( processor.readRegister(Processor.regV0), processor.readRegister(Processor.regA0), processor.readRegister(Processor.regA1), processor.readRegister(Processor.regA2), processor.readRegister(Processor.regA3)); processor.writeRegister(Processor.regV0, result); processor.advancePC(); break; default: Lib.debug(dbgProcess, "Unexpected exception: " + Processor.exceptionNames[cause]); handleExit(-1); Lib.assertNotReached("Unexpected exception"); } }
/** * Allocate and return a new process of the correct class. The class name is specified by the * <tt>nachos.conf</tt> key <tt>Kernel.processClassName</tt>. * * @return a new process of the correct class. */ public static UserProcess newUserProcess() { return (UserProcess) Lib.constructObject(Machine.getProcessClassName()); }
private void delay() { long time = Machine.timer().getTime(); int amount = 1000; ThreadedKernel.alarm.waitUntil(amount); Lib.my_assert(Machine.timer().getTime() >= time + amount); }
private void allocatePage(int vpn) { // System.out.println("TLBMiss: VPN:" + vpn + " of Process " + processID); TranslationEntry t = pageTable[vpn]; if (!t.valid) { // System.out.println("Allocating VPN: " + t.vpn); lock.acquire(); if (UserKernel.freePages.size() > 0) { int ppn = ((Integer) UserKernel.freePages.removeFirst()).intValue(); t.valid = true; if (!t.dirty) { t.ppn = ppn; IPT[ppn] = new IPTEntry(); IPT[ppn].process = this; IPT[ppn].tE = t; boolean isCoffSection = false; for (int s = 0; s < coff.getNumSections(); s++) { if (isCoffSection) { break; } CoffSection section = coff.getSection(s); if (section.getFirstVPN() > t.vpn) { continue; } for (int i = 0; i < section.getLength(); i++) { int svpn = section.getFirstVPN() + i; if (svpn == t.vpn) { section.loadPage(i, pinVirtualPage(t.vpn, false)); // System.out.println("VPN \"" + t.vpn + "\" is a COFF section"); // System.out.println("COFF section loaded into VPN \"" + t.vpn + "\" PPN \"" + // t.ppn + "\""); isCoffSection = true; break; } } } if (!isCoffSection) { // System.out.println("VPN \"" + t.vpn + "\" is NOT a COFF section"); // System.out.println("PPN \"" + t.ppn + "\" Zero'd Out"); byte[] data = new byte[Processor.pageSize]; // writeVirtualMemory(t.vpn, data, 0, Processor.pageSize); byte[] memory = Machine.processor().getMemory(); System.arraycopy(data, 0, memory, t.ppn * Processor.pageSize, Processor.pageSize); } } else // Dirty { // System.out.println("VPN \"" + t.vpn + "\" has been swapped out, swaping into // PPN \"" + ppn + "\""); int spn = t.ppn; byte[] data = new byte[pageSize]; byte[] memory = Machine.processor().getMemory(); OpenFile swap = ThreadedKernel.fileSystem.open(".Nachos.swp", false); swap.read(spn * pageSize, memory, ppn * pageSize, pageSize); swap.close(); t.ppn = ppn; // System.out.println(spn); freeSwapPages.set(spn, true); IPT[ppn] = new IPTEntry(); IPT[ppn].process = this; IPT[ppn].tE = t; // System.out.println("SPN \"" + spn + "\" has been swapped in."); } } else { syncTLB(); // Clock Algorithm unpinnedPageLock.acquire(); int numPinnedPages = 0; while (IPT[victim] == null || IPT[victim].tE.used || IPT[victim].pinCount) { if (IPT[victim] != null) { IPT[victim].tE.used = false; // System.out.println("PPN " + victim + " is used."); } if (IPT[victim].pinCount) { numPinnedPages++; // System.out.println("PPN " + victim + " is pinned."); } if (numPinnedPages == IPT.length) unpinnedPage.sleep(); // System.out.println("This Process is " + this.processID + " and the IPT's // process is " + IPT[victim].processID); victim = (victim + 1) % Machine.processor().getNumPhysPages(); } // System.out.println("PPN " + victim + " will be evicted."); unpinnedPageLock.release(); int evict = IPT[victim].tE.vpn; VMProcess evictedOwner = IPT[victim].process; int evictedPPN = victim; victim = (victim + 1) % Machine.processor().getNumPhysPages(); // System.out.println("Not enough pysical memory, evicting VPN \"" + evict + "\" of process // " + evictedOwner.processID); // Swap Files if (evictedOwner.isDirty(evict)) { // System.out.println("VPN \"" + evict + "\" is dirty, swapping out."); OpenFile swap = ThreadedKernel.fileSystem.open(".Nachos.swp", false); int spn = 0; for (spn = 0; spn < freeSwapPages.size(); spn++) { if (freeSwapPages.get(spn)) { break; } } if (spn == freeSwapPages.size()) { freeSwapPages.add(false); } else { freeSwapPages.set(spn, false); } UserKernel.freePages.add(evictedPPN); byte[] memory = Machine.processor().getMemory(); swap.write(spn * pageSize, memory, evictedPPN * pageSize, pageSize); swap.close(); if (evictedOwner.processID != this.processID) { evictedOwner.evict(evict, spn); } else { pageTable[evict].ppn = spn; pageTable[evict].valid = false; } for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.vpn == evict && tE.ppn == evictedPPN) { // System.out.println("TLBEntry " + i + " invalid"); tE.valid = false; Machine.processor().writeTLBEntry(i, tE); } } lock.release(); // System.out.println("VPN \"" + evict + "\" of Process " + this.processID + " // swapped out to SPN \"" + spn + "\"."); // Machine.processor().readTLBEntry(evict).valid = false; allocatePage(vpn); return; } else { if (evictedOwner.processID != this.processID) { // System.out.println("Evicted VPN " + evict + " of Process " + this.processID); evictedOwner.evict(evict); } else { pageTable[evict].valid = false; } UserKernel.freePages.add(evictedPPN); for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.vpn == evict && tE.ppn == evictedPPN) { // System.out.println("TLBEntry " + i + " invalid"); tE.valid = false; Machine.processor().writeTLBEntry(i, tE); } } lock.release(); allocatePage(vpn); return; } } lock.release(); } for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (!tE.valid) { // System.out.println("Evicted TLBEntry " + i); Machine.processor().writeTLBEntry(i, t); // System.out.println(t.valid); return; } } syncTLB(); int evictedEntry = (int) (Math.random() * Machine.processor().getTLBSize()); TranslationEntry tE = Machine.processor().readTLBEntry(evictedEntry); pageTable[tE.vpn] = tE; Machine.processor().writeTLBEntry(evictedEntry, t); // System.out.println("Evicted TLBEntry " + evictedEntry + " randomly"); // System.out.println("TE entered is VPN \"" + t.vpn + "\" PPN \"" + t.ppn + "\""); }
public void handleTLBMiss() { int vaddr = Machine.processor().readRegister(Processor.regBadVAddr); int vpn = Processor.pageFromAddress(vaddr); allocatePage(vpn); }
/** * Restore the state of this process after a context switch. Called by * <tt>UThread.restoreState()</tt>. */ public void restoreState() { Machine.processor().setPageTable(pageTable); }
/** A <tt>UserProcess</tt> that supports demand-paging. */ public class VMProcess extends UserProcess { /** Allocate a new process. */ public VMProcess() { super(); } /** * Save the state of this process in preparation for a context switch. Called by * <tt>UThread.saveState()</tt>. */ public void saveState() { for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.valid) { pageTable[tE.vpn].dirty = tE.dirty; pageTable[tE.vpn].used = tE.used; } tE.valid = false; Machine.processor().writeTLBEntry(i, tE); // savedState[i] = tE.vpn; } } /** * Restore the state of this process after a context switch. Called by * <tt>UThread.restoreState()</tt>. */ public void restoreState() { /*for(int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); tE.valid = false; Machine.processor().writeTLBEntry(i, tE); } for(int i = 0; i < Machine.processor().getTLBSize(); i++) { if(pageTable[savedState[i]].valid) { Machine.processor().writeTLBEntry(i, pageTable[savedState[i]]); } }*/ } /** * Initializes page tables for this process so that the executable can be demand-paged. * * @return <tt>true</tt> if successful. */ protected boolean loadSections() { UserKernel.memoryLock.acquire(); pageTable = new TranslationEntry[numPages]; for (int vpn = 0; vpn < numPages; vpn++) { pageTable[vpn] = new TranslationEntry(vpn, -1, false, false, false, false); } UserKernel.memoryLock.release(); // load sections for (int s = 0; s < coff.getNumSections(); s++) { CoffSection section = coff.getSection(s); Lib.debug( dbgProcess, "\tinitializing " + section.getName() + " section (" + section.getLength() + " pages)"); for (int i = 0; i < section.getLength(); i++) { int vpn = section.getFirstVPN() + i; pageTable[vpn].readOnly = section.isReadOnly(); // section.loadPage(i, pinVirtualPage(vpn, false)); } } return true; } /** Release any resources allocated by <tt>loadSections()</tt>. */ protected void unloadSections() { for (int vpn = 0; vpn < pageTable.length; vpn++) { if (pageTable[vpn].valid) { UserKernel.freePages.add(new Integer(pageTable[vpn].ppn)); // IPT[pageTable[vpn].ppn] = null; } } } /** * Handle a user exception. Called by <tt>UserKernel.exceptionHandler()</tt> . The <i>cause</i> * argument identifies which exception occurred; see the <tt>Processor.exceptionZZZ</tt> * constants. * * @param cause the user exception that occurred. */ public void handleException(int cause) { Processor processor = Machine.processor(); switch (cause) { case Processor.exceptionTLBMiss: handleTLBMiss(); break; default: super.handleException(cause); break; } } protected int pinVirtualPage(int vpn, boolean isUserWrite) { int ppn = super.pinVirtualPage(vpn, isUserWrite); if (ppn >= 0) { if (isUserWrite) { IPT[ppn].pinCount = true; } } else { if (vpn < 0 || vpn >= pageTable.length) return -1; if (!pageTable[vpn].valid) { allocatePage(vpn); } ppn = super.pinVirtualPage(vpn, isUserWrite); if (isUserWrite) { IPT[ppn].pinCount = true; } } return ppn; } protected void unpinVirtualPage(int vpn) { int ppn = super.pinVirtualPage(vpn, false); if (ppn >= 0) { IPT[ppn].pinCount = false; unpinnedPageLock.acquire(); unpinnedPage.wake(); unpinnedPageLock.release(); } } public void handleTLBMiss() { int vaddr = Machine.processor().readRegister(Processor.regBadVAddr); int vpn = Processor.pageFromAddress(vaddr); allocatePage(vpn); } private void syncTLB() { for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.valid) { pageTable[tE.vpn].dirty = tE.dirty; pageTable[tE.vpn].used = tE.used; } } } private void allocatePage(int vpn) { // System.out.println("TLBMiss: VPN:" + vpn + " of Process " + processID); TranslationEntry t = pageTable[vpn]; if (!t.valid) { // System.out.println("Allocating VPN: " + t.vpn); lock.acquire(); if (UserKernel.freePages.size() > 0) { int ppn = ((Integer) UserKernel.freePages.removeFirst()).intValue(); t.valid = true; if (!t.dirty) { t.ppn = ppn; IPT[ppn] = new IPTEntry(); IPT[ppn].process = this; IPT[ppn].tE = t; boolean isCoffSection = false; for (int s = 0; s < coff.getNumSections(); s++) { if (isCoffSection) { break; } CoffSection section = coff.getSection(s); if (section.getFirstVPN() > t.vpn) { continue; } for (int i = 0; i < section.getLength(); i++) { int svpn = section.getFirstVPN() + i; if (svpn == t.vpn) { section.loadPage(i, pinVirtualPage(t.vpn, false)); // System.out.println("VPN \"" + t.vpn + "\" is a COFF section"); // System.out.println("COFF section loaded into VPN \"" + t.vpn + "\" PPN \"" + // t.ppn + "\""); isCoffSection = true; break; } } } if (!isCoffSection) { // System.out.println("VPN \"" + t.vpn + "\" is NOT a COFF section"); // System.out.println("PPN \"" + t.ppn + "\" Zero'd Out"); byte[] data = new byte[Processor.pageSize]; // writeVirtualMemory(t.vpn, data, 0, Processor.pageSize); byte[] memory = Machine.processor().getMemory(); System.arraycopy(data, 0, memory, t.ppn * Processor.pageSize, Processor.pageSize); } } else // Dirty { // System.out.println("VPN \"" + t.vpn + "\" has been swapped out, swaping into // PPN \"" + ppn + "\""); int spn = t.ppn; byte[] data = new byte[pageSize]; byte[] memory = Machine.processor().getMemory(); OpenFile swap = ThreadedKernel.fileSystem.open(".Nachos.swp", false); swap.read(spn * pageSize, memory, ppn * pageSize, pageSize); swap.close(); t.ppn = ppn; // System.out.println(spn); freeSwapPages.set(spn, true); IPT[ppn] = new IPTEntry(); IPT[ppn].process = this; IPT[ppn].tE = t; // System.out.println("SPN \"" + spn + "\" has been swapped in."); } } else { syncTLB(); // Clock Algorithm unpinnedPageLock.acquire(); int numPinnedPages = 0; while (IPT[victim] == null || IPT[victim].tE.used || IPT[victim].pinCount) { if (IPT[victim] != null) { IPT[victim].tE.used = false; // System.out.println("PPN " + victim + " is used."); } if (IPT[victim].pinCount) { numPinnedPages++; // System.out.println("PPN " + victim + " is pinned."); } if (numPinnedPages == IPT.length) unpinnedPage.sleep(); // System.out.println("This Process is " + this.processID + " and the IPT's // process is " + IPT[victim].processID); victim = (victim + 1) % Machine.processor().getNumPhysPages(); } // System.out.println("PPN " + victim + " will be evicted."); unpinnedPageLock.release(); int evict = IPT[victim].tE.vpn; VMProcess evictedOwner = IPT[victim].process; int evictedPPN = victim; victim = (victim + 1) % Machine.processor().getNumPhysPages(); // System.out.println("Not enough pysical memory, evicting VPN \"" + evict + "\" of process // " + evictedOwner.processID); // Swap Files if (evictedOwner.isDirty(evict)) { // System.out.println("VPN \"" + evict + "\" is dirty, swapping out."); OpenFile swap = ThreadedKernel.fileSystem.open(".Nachos.swp", false); int spn = 0; for (spn = 0; spn < freeSwapPages.size(); spn++) { if (freeSwapPages.get(spn)) { break; } } if (spn == freeSwapPages.size()) { freeSwapPages.add(false); } else { freeSwapPages.set(spn, false); } UserKernel.freePages.add(evictedPPN); byte[] memory = Machine.processor().getMemory(); swap.write(spn * pageSize, memory, evictedPPN * pageSize, pageSize); swap.close(); if (evictedOwner.processID != this.processID) { evictedOwner.evict(evict, spn); } else { pageTable[evict].ppn = spn; pageTable[evict].valid = false; } for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.vpn == evict && tE.ppn == evictedPPN) { // System.out.println("TLBEntry " + i + " invalid"); tE.valid = false; Machine.processor().writeTLBEntry(i, tE); } } lock.release(); // System.out.println("VPN \"" + evict + "\" of Process " + this.processID + " // swapped out to SPN \"" + spn + "\"."); // Machine.processor().readTLBEntry(evict).valid = false; allocatePage(vpn); return; } else { if (evictedOwner.processID != this.processID) { // System.out.println("Evicted VPN " + evict + " of Process " + this.processID); evictedOwner.evict(evict); } else { pageTable[evict].valid = false; } UserKernel.freePages.add(evictedPPN); for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.vpn == evict && tE.ppn == evictedPPN) { // System.out.println("TLBEntry " + i + " invalid"); tE.valid = false; Machine.processor().writeTLBEntry(i, tE); } } lock.release(); allocatePage(vpn); return; } } lock.release(); } for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (!tE.valid) { // System.out.println("Evicted TLBEntry " + i); Machine.processor().writeTLBEntry(i, t); // System.out.println(t.valid); return; } } syncTLB(); int evictedEntry = (int) (Math.random() * Machine.processor().getTLBSize()); TranslationEntry tE = Machine.processor().readTLBEntry(evictedEntry); pageTable[tE.vpn] = tE; Machine.processor().writeTLBEntry(evictedEntry, t); // System.out.println("Evicted TLBEntry " + evictedEntry + " randomly"); // System.out.println("TE entered is VPN \"" + t.vpn + "\" PPN \"" + t.ppn + "\""); } public void evict(int vpn, int spn) { pageTable[vpn].ppn = spn; pageTable[vpn].valid = false; } public void evict(int vpn) { pageTable[vpn].valid = false; } public boolean isDirty(int vpn) { return pageTable[vpn].dirty; } private static final int pageSize = Processor.pageSize; private static final char dbgProcess = 'a'; private static final char dbgVM = 'v'; private static int victim = 0; private static LinkedList<Boolean> freeSwapPages = new LinkedList<Boolean>(); private static IPTEntry[] IPT = new IPTEntry[Machine.processor().getNumPhysPages()]; private class IPTEntry { public VMProcess process; public TranslationEntry tE; public boolean pinCount; } public static Lock unpinnedPageLock = new Lock(); public static Condition unpinnedPage = new Condition(unpinnedPageLock); public static Lock lock = new Lock(); private int[] savedState = new int[Machine.processor().getTLBSize()]; }