710 lines
20 KiB
Java
710 lines
20 KiB
Java
package nachos.userprog;
|
|
|
|
import nachos.machine.*;
|
|
import nachos.threads.*;
|
|
import nachos.userprog.*;
|
|
|
|
import java.io.EOFException;
|
|
import java.util.HashSet;
|
|
|
|
/**
|
|
* Encapsulates the state of a user process that is not contained in its
|
|
* user thread (or threads). This includes its address translation state, a
|
|
* file table, and information about the program being executed.
|
|
*
|
|
* <p>
|
|
* This class is extended by other classes to support additional functionality
|
|
* (such as additional syscalls).
|
|
*
|
|
* @see nachos.vm.VMProcess
|
|
* @see nachos.network.NetProcess
|
|
*/
|
|
public class UserProcess {
|
|
/**
|
|
* Allocate a new process.
|
|
*/
|
|
public UserProcess() {
|
|
int numPhysPages = Machine.processor().getNumPhysPages();
|
|
pageTable = new TranslationEntry[numPhysPages];
|
|
cond_lock=new Lock();
|
|
cond=new Condition(cond_lock);
|
|
/*
|
|
for (int i=0; i<numPhysPages; i++)
|
|
pageTable[i] = new TranslationEntry(i,i, true,false,false,false);
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* 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() {
|
|
//TODO: Remove this line!!!
|
|
return new UserProcess();
|
|
//return (UserProcess)Lib.constructObject(Machine.getProcessClassName());
|
|
}
|
|
|
|
/**
|
|
* Execute the specified program with the specified arguments. Attempts to
|
|
* load the program, and then forks a thread to run it.
|
|
*
|
|
* @param name the name of the file containing the executable.
|
|
* @param args the arguments to pass to the executable.
|
|
* @return <tt>true</tt> if the program was successfully executed.
|
|
*/
|
|
public boolean execute(String name, String[] args) {
|
|
if (!load(name, args))
|
|
return false;
|
|
|
|
descs=new OpenFile[16];
|
|
descs[0]=UserKernel.console.openForReading();
|
|
descs[1]=UserKernel.console.openForWriting();
|
|
for(int i=2;i<16;i++)
|
|
descs[i]=null;
|
|
|
|
UserKernel.process_lock.P();
|
|
//Simply increment the counter for now
|
|
UserKernel.process_pool_size+=1;
|
|
pid=UserKernel.process_pool_size;
|
|
UserKernel.process_table.put(pid,this);
|
|
UserKernel.process_tree.put(pid,new HashSet<Integer>());
|
|
UserKernel.process_fin.put(pid,0);
|
|
UserKernel.process_lock.V();
|
|
|
|
thread=new UThread(this);
|
|
thread.setName(name).fork();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Save the state of this process in preparation for a context switch.
|
|
* Called by <tt>UThread.saveState()</tt>.
|
|
*/
|
|
public void saveState() {
|
|
}
|
|
|
|
/**
|
|
* Restore the state of this process after a context switch. Called by
|
|
* <tt>UThread.restoreState()</tt>.
|
|
*/
|
|
public void restoreState() {
|
|
Machine.processor().setPageTable(pageTable);
|
|
}
|
|
|
|
/**
|
|
* Read a null-terminated string from this process's virtual memory. Read
|
|
* at most <tt>maxLength + 1</tt> bytes from the specified address, search
|
|
* for the null terminator, and convert it to a <tt>java.lang.String</tt>,
|
|
* without including the null terminator. If no null terminator is found,
|
|
* returns <tt>null</tt>.
|
|
*
|
|
* @param vaddr the starting virtual address of the null-terminated
|
|
* string.
|
|
* @param maxLength the maximum number of characters in the string,
|
|
* not including the null terminator.
|
|
* @return the string read, or <tt>null</tt> if no null terminator was
|
|
* found.
|
|
*/
|
|
public String readVirtualMemoryString(int vaddr, int maxLength) {
|
|
Lib.assertTrue(maxLength >= 0);
|
|
|
|
byte[] bytes = new byte[maxLength+1];
|
|
|
|
int bytesRead = readVirtualMemory(vaddr, bytes);
|
|
|
|
/*
|
|
System.out.println("Read:");
|
|
for(int i=0;i<bytesRead;i++)
|
|
System.out.println(bytes[i]);
|
|
*/
|
|
|
|
for (int length=0; length<bytesRead; length++) {
|
|
if (bytes[length] == 0)
|
|
return new String(bytes, 0, length);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Transfer data from this process's virtual memory to all of the specified
|
|
* array. Same as <tt>readVirtualMemory(vaddr, data, 0, data.length)</tt>.
|
|
*
|
|
* @param vaddr the first byte of virtual memory to read.
|
|
* @param data the array where the data will be stored.
|
|
* @return the number of bytes successfully transferred.
|
|
*/
|
|
public int readVirtualMemory(int vaddr, byte[] data) {
|
|
return readVirtualMemory(vaddr, data, 0, data.length);
|
|
}
|
|
|
|
/**
|
|
* Transfer data from this process's virtual memory to the specified array.
|
|
* 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 read.
|
|
* @param data the array where the data will be stored.
|
|
* @param offset the first byte to write in the array.
|
|
* @param length the number of bytes to transfer from virtual memory to
|
|
* the array.
|
|
* @return the number of bytes successfully transferred.
|
|
*/
|
|
public int readVirtualMemory(int vaddr, byte[] data, int offset, int length)
|
|
{
|
|
byte[] memory = Machine.processor().getMemory();
|
|
|
|
int vpn=vaddr/pageSize;
|
|
if(vaddr<0||vpn>=numPages)
|
|
return 0;
|
|
|
|
int total=0;
|
|
for(int i=vpn;i<numPages;i++)
|
|
{
|
|
int amount=Math.min(length,(i+1)*pageSize-vaddr);
|
|
int ppn_offs=vaddr-i*pageSize;
|
|
if(amount<=0)
|
|
break;
|
|
System.arraycopy(memory,pageTable[i].ppn*pageSize+ppn_offs,data,offset,amount);
|
|
offset+=amount;
|
|
vaddr+=amount;
|
|
length-=amount;
|
|
total+=amount;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
/**
|
|
* Transfer all data from the specified array to this process's virtual
|
|
* memory.
|
|
* Same as <tt>writeVirtualMemory(vaddr, data, 0, data.length)</tt>.
|
|
*
|
|
* @param vaddr the first byte of virtual memory to write.
|
|
* @param data the array containing the data to transfer.
|
|
* @return the number of bytes successfully transferred.
|
|
*/
|
|
public int writeVirtualMemory(int vaddr, byte[] data) {
|
|
return writeVirtualMemory(vaddr, data, 0, data.length);
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
byte[] memory = Machine.processor().getMemory();
|
|
|
|
int vpn=vaddr/pageSize;
|
|
if(vaddr<0||vpn>=numPages)
|
|
return 0;
|
|
|
|
int total=0;
|
|
for(int i=vpn;i<numPages;i++)
|
|
{
|
|
int amount=Math.min(length,(i+1)*pageSize-vaddr);
|
|
int ppn_offs=vaddr-i*pageSize;
|
|
if(amount<=0)
|
|
break;
|
|
System.arraycopy(data,offset,memory,pageTable[i].ppn*pageSize+ppn_offs,amount);
|
|
offset+=amount;
|
|
vaddr+=amount;
|
|
length-=amount;
|
|
total+=amount;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
/**
|
|
* Load the executable with the specified name into this process, and
|
|
* prepare to pass it the specified arguments. Opens the executable, reads
|
|
* its header information, and copies sections and arguments into this
|
|
* process's virtual memory.
|
|
*
|
|
* @param name the name of the file containing the executable.
|
|
* @param args the arguments to pass to the executable.
|
|
* @return <tt>true</tt> if the executable was successfully loaded.
|
|
*/
|
|
private boolean load(String name, String[] args) {
|
|
Lib.debug(dbgProcess, "UserProcess.load(\"" + name + "\")");
|
|
|
|
OpenFile executable = ThreadedKernel.fileSystem.open(name, false);
|
|
if (executable == null) {
|
|
Lib.debug(dbgProcess, "\topen failed");
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
coff = new Coff(executable);
|
|
}
|
|
catch (EOFException e) {
|
|
executable.close();
|
|
Lib.debug(dbgProcess, "\tcoff load failed");
|
|
return false;
|
|
}
|
|
|
|
// make sure the sections are contiguous and start at page 0
|
|
numPages = 0;
|
|
for (int s=0; s<coff.getNumSections(); s++) {
|
|
CoffSection section = coff.getSection(s);
|
|
if (section.getFirstVPN() != numPages) {
|
|
coff.close();
|
|
Lib.debug(dbgProcess, "\tfragmented executable");
|
|
return false;
|
|
}
|
|
numPages += section.getLength();
|
|
}
|
|
|
|
// make sure the argv array will fit in one page
|
|
byte[][] argv = new byte[args.length][];
|
|
int argsSize = 0;
|
|
for (int i=0; i<args.length; i++) {
|
|
argv[i] = args[i].getBytes();
|
|
// 4 bytes for argv[] pointer; then string plus one for null byte
|
|
argsSize += 4 + argv[i].length + 1;
|
|
}
|
|
if (argsSize > pageSize) {
|
|
coff.close();
|
|
Lib.debug(dbgProcess, "\targuments too long");
|
|
return false;
|
|
}
|
|
|
|
// program counter initially points at the program entry point
|
|
initialPC = coff.getEntryPoint();
|
|
|
|
// next comes the stack; stack pointer initially points to top of it
|
|
numPages += stackPages;
|
|
initialSP = numPages*pageSize;
|
|
|
|
// and finally reserve 1 page for arguments
|
|
numPages++;
|
|
|
|
if (!loadSections())
|
|
return false;
|
|
|
|
// store arguments in last page
|
|
int entryOffset = (numPages-1)*pageSize;
|
|
int stringOffset = entryOffset + args.length*4;
|
|
|
|
this.argc = args.length;
|
|
this.argv = entryOffset;
|
|
|
|
for (int i=0; i<argv.length; i++) {
|
|
byte[] stringOffsetBytes = Lib.bytesFromInt(stringOffset);
|
|
Lib.assertTrue(writeVirtualMemory(entryOffset,stringOffsetBytes) == 4);
|
|
entryOffset += 4;
|
|
Lib.assertTrue(writeVirtualMemory(stringOffset, argv[i]) ==
|
|
argv[i].length);
|
|
stringOffset += argv[i].length;
|
|
Lib.assertTrue(writeVirtualMemory(stringOffset,new byte[] { 0 }) == 1);
|
|
stringOffset += 1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 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()
|
|
{
|
|
UserKernel.fp_lock.P();
|
|
int num_free_pages=UserKernel.free_pages.size();
|
|
if(numPages>num_free_pages)
|
|
{
|
|
coff.close();
|
|
Lib.debug(dbgProcess,"\tinsufficient physical memory");
|
|
UserKernel.fp_lock.V();
|
|
return false;
|
|
}
|
|
|
|
//allocate
|
|
for(int i=0;i<numPages;i++)
|
|
{
|
|
Integer x=UserKernel.free_pages.getFirst();
|
|
pageTable[i]=new TranslationEntry(i,x,true,false,false,false);
|
|
Lib.debug(dbgProcess,"\tassigning physical page "+x);
|
|
UserKernel.free_pages.remove(x);
|
|
}
|
|
|
|
// 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;
|
|
section.loadPage(i, pageTable[vpn].ppn);
|
|
}
|
|
}
|
|
|
|
UserKernel.fp_lock.V();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Release any resources allocated by <tt>loadSections()</tt>.
|
|
*/
|
|
protected void unloadSections()
|
|
{
|
|
UserKernel.fp_lock.P();
|
|
for(int i=0;i<numPages;i++)
|
|
{
|
|
UserKernel.free_pages.add(pageTable[i].ppn);
|
|
pageTable[i]=null;
|
|
}
|
|
UserKernel.fp_lock.V();
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* Handle the halt() system call.
|
|
*/
|
|
private int handleHalt()
|
|
{
|
|
if(pid==1)
|
|
Machine.halt();
|
|
return 0;
|
|
}
|
|
|
|
|
|
private static final int
|
|
syscallHalt = 0,
|
|
syscallExit = 1,
|
|
syscallExec = 2,
|
|
syscallJoin = 3,
|
|
syscallCreate = 4,
|
|
syscallOpen = 5,
|
|
syscallRead = 6,
|
|
syscallWrite = 7,
|
|
syscallClose = 8,
|
|
syscallUnlink = 9;
|
|
|
|
public int handleExit(int status)
|
|
{
|
|
UserKernel.process_lock.P();
|
|
UserKernel.process_fin.put(pid,1);
|
|
UserKernel.process_return.put(pid,status);
|
|
UserKernel.process_lock.V();
|
|
|
|
cond_lock.acquire();
|
|
cond.wakeAll();
|
|
cond_lock.release();
|
|
|
|
//Do some extra cleanup
|
|
unloadSections();
|
|
coff.close();
|
|
|
|
for(int i=0;i<16;i++)
|
|
if(descs[i]!=null)
|
|
descs[i].close();
|
|
|
|
if(pid==1)
|
|
Machine.halt();
|
|
|
|
thread.finish();
|
|
|
|
return 0;
|
|
}
|
|
|
|
private byte[] bytearray_create_safe(int size)
|
|
{
|
|
if(size<0||size>numPages*pageSize)
|
|
return null;
|
|
return new byte[size];
|
|
}
|
|
|
|
/**
|
|
* Handle a syscall exception. Called by <tt>handleException()</tt>. The
|
|
* <i>syscall</i> argument identifies which syscall the user executed:
|
|
*
|
|
* <table>
|
|
* <tr><td>syscall#</td><td>syscall prototype</td></tr>
|
|
* <tr><td>0</td><td><tt>void halt();</tt></td></tr>
|
|
* <tr><td>1</td><td><tt>void exit(int status);</tt></td></tr>
|
|
* <tr><td>2</td><td><tt>int exec(char *name, int argc, char **argv);
|
|
* </tt></td></tr>
|
|
* <tr><td>3</td><td><tt>int join(int pid, int *status);</tt></td></tr>
|
|
* <tr><td>4</td><td><tt>int creat(char *name);</tt></td></tr>
|
|
* <tr><td>5</td><td><tt>int open(char *name);</tt></td></tr>
|
|
* <tr><td>6</td><td><tt>int read(int fd, char *buffer, int size);
|
|
* </tt></td></tr>
|
|
* <tr><td>7</td><td><tt>int write(int fd, char *buffer, int size);
|
|
* </tt></td></tr>
|
|
* <tr><td>8</td><td><tt>int close(int fd);</tt></td></tr>
|
|
* <tr><td>9</td><td><tt>int unlink(char *name);</tt></td></tr>
|
|
* </table>
|
|
*
|
|
* @param syscall the syscall number.
|
|
* @param a0 the first syscall argument.
|
|
* @param a1 the second syscall argument.
|
|
* @param a2 the third syscall argument.
|
|
* @param a3 the fourth syscall argument.
|
|
* @return the value to be returned to the user.
|
|
*/
|
|
public int handleSyscall(int syscall, int a0, int a1, int a2, int a3)
|
|
{
|
|
String fn;
|
|
String[] argz;
|
|
byte[] buf;
|
|
int len,val,tmp;
|
|
UserProcess child;
|
|
boolean status;
|
|
switch (syscall)
|
|
{
|
|
case syscallHalt:
|
|
return handleHalt();
|
|
|
|
case syscallExit:
|
|
return handleExit(a0);
|
|
|
|
case syscallExec:
|
|
fn=readVirtualMemoryString(a0,256);
|
|
if(fn!=null&&fn.lastIndexOf('.')!=-1&&fn.substring(fn.lastIndexOf('.')).equals(".coff"))
|
|
{
|
|
buf=bytearray_create_safe(4*a1);
|
|
if(buf==null)
|
|
return -1;
|
|
argz=new String[a1];
|
|
readVirtualMemory(a2,buf,0,4*a1);
|
|
tmp=0;
|
|
for(int i=0;i<4*a1;i++)
|
|
{
|
|
tmp+=((((int)(buf[i]))&0xFF)<<(8*(i%4)));
|
|
if(i%4==3)
|
|
{
|
|
argz[i/4]=readVirtualMemoryString(tmp,256);
|
|
if(argz[i/4]==null)
|
|
argz[i/4]=new String();
|
|
tmp=0;
|
|
}
|
|
}
|
|
child=UserProcess.newUserProcess();
|
|
status=child.execute(fn,argz);
|
|
if(status)
|
|
{
|
|
UserKernel.process_lock.P();
|
|
UserKernel.process_tree.get(pid).add(child.pid);
|
|
UserKernel.process_lock.V();
|
|
return child.pid;
|
|
}
|
|
return -1;
|
|
}
|
|
return -1;
|
|
|
|
case syscallJoin:
|
|
UserKernel.process_lock.P();
|
|
if(!UserKernel.process_tree.get(pid).contains(a0))
|
|
{
|
|
UserKernel.process_lock.V();
|
|
return -1;
|
|
}
|
|
tmp=UserKernel.process_fin.get(a0);
|
|
if(tmp==1)
|
|
{
|
|
val=UserKernel.process_return.get(a0);
|
|
UserKernel.process_lock.V();
|
|
}
|
|
else
|
|
{
|
|
child=UserKernel.process_table.get(a0);
|
|
UserKernel.process_lock.V();
|
|
|
|
child.cond_lock.acquire();
|
|
child.cond.sleep();
|
|
child.cond_lock.release();
|
|
|
|
UserKernel.process_lock.P();
|
|
val=UserKernel.process_return.get(a0);
|
|
UserKernel.process_lock.V();
|
|
}
|
|
buf=new byte[4];
|
|
for(int i=0;i<4;i++)
|
|
buf[i]=(byte)(((val>>(8*i))%(1<<8))&0xFF);
|
|
writeVirtualMemory(a1,buf,0,4);
|
|
if(val==-1)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
|
|
case syscallCreate:
|
|
fn=readVirtualMemoryString(a0,256);
|
|
if(fn!=null)
|
|
{
|
|
OpenFile tf=ThreadedKernel.fileSystem.open(fn,true);
|
|
if(tf==null)
|
|
return -1;
|
|
for(int i=0;i<16;i++)
|
|
if(descs[i]==null)
|
|
{
|
|
descs[i]=tf;
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
return -1;
|
|
|
|
case syscallOpen:
|
|
fn=readVirtualMemoryString(a0,256);
|
|
if(fn!=null)
|
|
{
|
|
OpenFile tf=ThreadedKernel.fileSystem.open(fn,false);
|
|
if(tf==null)
|
|
return -1;
|
|
for(int i=2;i<16;i++)
|
|
if(descs[i]==null)
|
|
{
|
|
descs[i]=tf;
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
return -1;
|
|
|
|
case syscallRead:
|
|
if(a0<0||a0>=16)
|
|
return -1;
|
|
if(descs[a0]==null)
|
|
return -1;
|
|
buf=bytearray_create_safe(a2);
|
|
if(buf==null)
|
|
return -1;
|
|
len=descs[a0].read(buf,0,a2);
|
|
if(len<0)
|
|
return -1;
|
|
return writeVirtualMemory(a1,buf,0,len);
|
|
|
|
case syscallWrite:
|
|
if(a0<0||a0>=16)
|
|
return -1;
|
|
if(descs[a0]==null)
|
|
return -1;
|
|
buf=bytearray_create_safe(a2);
|
|
if(buf==null)
|
|
return -1;
|
|
len=readVirtualMemory(a1,buf,0,a2);
|
|
return descs[a0].write(buf,0,len);
|
|
|
|
case syscallClose:
|
|
if(a0<0||a0>=16)
|
|
return -1;
|
|
if(descs[a0]!=null)
|
|
descs[a0].close();
|
|
descs[a0]=null;
|
|
return 0;
|
|
|
|
case syscallUnlink:
|
|
fn=readVirtualMemoryString(a0,256);
|
|
if(fn!=null)
|
|
{
|
|
ThreadedKernel.fileSystem.remove(fn);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
|
|
default:
|
|
Lib.debug(dbgProcess, "Unknown syscall " + syscall);
|
|
Lib.assertNotReached("Unknown system call!");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 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");
|
|
}
|
|
}
|
|
|
|
/** The program being run by this process. */
|
|
protected Coff coff;
|
|
|
|
/** This process's page table. */
|
|
protected TranslationEntry[] pageTable;
|
|
/** The number of contiguous pages occupied by the program. */
|
|
protected int numPages;
|
|
|
|
/** The number of pages in the program's stack. */
|
|
protected final int stackPages = 8;
|
|
|
|
private int initialPC, initialSP;
|
|
private int argc, argv;
|
|
|
|
private static final int pageSize = Processor.pageSize;
|
|
private static final char dbgProcess = 'a';
|
|
private OpenFile descs[];
|
|
|
|
public int pid;
|
|
public Lock cond_lock;
|
|
public Condition cond;
|
|
|
|
private UThread thread;
|
|
}
|