p1/machine/CoffSection.java

229 lines
6.3 KiB
Java

// 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';
}