// PART OF THE MACHINE SIMULATION. DO NOT CHANGE. package nachos.machine; import nachos.security.*; import java.io.EOFException; import java.util.Arrays; /** * A <tt>CoffSection</tt> manages a single section within a COFF executable. */ public class CoffSection { /** * Allocate a new COFF section with the specified parameters. * * @param coff the COFF object to which this section belongs. * @param name the COFF name of this section. * @param executable <tt>true</tt> if this section contains code. * @param readOnly <tt>true</tt> if this section is read-only. * @param numPages the number of virtual pages in this section. * @param firstVPN the first virtual page number used by this. */ protected CoffSection(Coff coff, String name, boolean executable, boolean readOnly, int numPages, int firstVPN) { this.coff = coff; this.name = name; this.executable = executable; this.readOnly = readOnly; this.numPages = numPages; this.firstVPN = firstVPN; file = null; size = 0; contentOffset = 0; initialized = true; } /** * Load a COFF section from an executable. * * @param file the file containing the executable. * @param headerOffset the offset of the section header in the * executable. * * @exception EOFException if an error occurs. */ public CoffSection(OpenFile file, Coff coff, int headerOffset) throws EOFException { this.file = file; this.coff = coff; Lib.assertTrue(headerOffset >= 0); if (headerOffset+headerLength > file.length()) { Lib.debug(dbgCoffSection, "\tsection header truncated"); throw new EOFException(); } byte[] buf = new byte[headerLength]; Lib.strictReadFile(file, headerOffset, buf, 0, headerLength); name = Lib.bytesToString(buf, 0, 8); int vaddr = Lib.bytesToInt(buf, 12); size = Lib.bytesToInt(buf, 16); contentOffset = Lib.bytesToInt(buf, 20); int numRelocations = Lib.bytesToUnsignedShort(buf, 32); int flags = Lib.bytesToInt(buf, 36); if (numRelocations != 0) { Lib.debug(dbgCoffSection, "\tsection needs relocation"); throw new EOFException(); } switch (flags & 0x0FFF) { case 0x0020: executable = true; readOnly = true; initialized = true; break; case 0x0040: executable = false; readOnly = false; initialized = true; break; case 0x0080: executable = false; readOnly = false; initialized = false; break; case 0x0100: executable = false; readOnly = true; initialized = true; break; default: Lib.debug(dbgCoffSection, "\tinvalid section flags: " + flags); throw new EOFException(); } if (vaddr%Processor.pageSize != 0 || size < 0 || initialized && (contentOffset < 0 || contentOffset+size > file.length())) { Lib.debug(dbgCoffSection, "\tinvalid section addresses: " + "vaddr=" + vaddr + " size=" + size + " contentOffset=" + contentOffset); throw new EOFException(); } numPages = Lib.divRoundUp(size, Processor.pageSize); firstVPN = vaddr / Processor.pageSize; } /** * Return the COFF object used to load this executable instance. * * @return the COFF object corresponding to this section. */ public Coff getCoff() { return coff; } /** * Return the name of this section. * * @return the name of this section. */ public String getName() { return name; } /** * Test whether this section is read-only. * * @return <tt>true</tt> if this section should never be written. */ public boolean isReadOnly() { return readOnly; } /** * Test whether this section is initialized. Loading a page from an * initialized section requires a disk access, while loading a page from an * uninitialized section requires only zero-filling the page. * * @return <tt>true</tt> if this section contains initialized data in the * executable. */ public boolean isInitialzed() { return initialized; } /** * Return the length of this section in pages. * * @return the number of pages in this section. */ public int getLength() { return numPages; } /** * Return the first virtual page number used by this section. * * @return the first virtual page number used by this section. */ public int getFirstVPN() { return firstVPN; } /** * Load a page from this segment into physical memory. * * @param spn the page number within this segment. * @param ppn the physical page to load into. */ public void loadPage(int spn, int ppn) { Lib.assertTrue(file != null); Lib.assertTrue(spn>=0 && spn<numPages); Lib.assertTrue(ppn>=0 && ppn<Machine.processor().getNumPhysPages()); int pageSize = Processor.pageSize; byte[] memory = Machine.processor().getMemory(); int paddr = ppn*pageSize; int faddr = contentOffset + spn*pageSize; int initlen; if (!initialized) initlen = 0; else if (spn == numPages-1) /** initlen = size % pageSize; * Bug identified by Steven Schlansker 3/20/08 * Bug fix by Michael Rauser */ initlen = (size==pageSize) ? pageSize : (size%pageSize); else initlen = pageSize; if (initlen > 0) Lib.strictReadFile(file, faddr, memory, paddr, initlen); Arrays.fill(memory, paddr+initlen, paddr+pageSize, (byte) 0); } /** The COFF object to which this section belongs. */ protected Coff coff; /** The COFF name of this section. */ protected String name; /** True if this section contains code. */ protected boolean executable; /** True if this section is read-only. */ protected boolean readOnly; /** True if this section contains initialized data. */ protected boolean initialized; /** The number of virtual pages in this section. */ protected int numPages; /** The first virtual page number used by this section. */ protected int firstVPN; private OpenFile file; private int contentOffset, size; /** The length of a COFF section header. */ public static final int headerLength = 40; private static final char dbgCoffSection = 'c'; }