/** * 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; }
/** * 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; } }
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 + "\""); }