Пример #1
0
  /**
   * 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;
  }
Пример #2
0
  /**
   * 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;
    }
  }
Пример #3
0
  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 + "\"");

  }