/**
* ****************************************************************************
* Copyright (c) 2010-2016 by Min Cai (min.cai.china@gmail.com).
* <p>
* This file is part of the Archimulator multicore architectural simulator.
* <p>
* Archimulator is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p>
* Archimulator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with Archimulator. If not, see <http://www.gnu.org/licenses/>.
* ****************************************************************************
*/
package archimulator.os;
import archimulator.common.*;
import archimulator.isa.ArchitecturalRegisterFile;
import archimulator.isa.event.SystemCallExecutedEvent;
import archimulator.os.event.*;
import archimulator.os.signal.SignalMask;
import archimulator.util.buffer.CircularByteBuffer;
import org.jruby.ext.posix.FileStat;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* System call emulation.
*
* @author Min Cai
*/
public class SystemCallEmulation
extends BasicSimulationObject<CPUExperiment, Simulation>
implements SimulationObject<CPUExperiment, Simulation> {
/**
* System control arguments.
*/
private class SysctrlArgs {
private int name;
private int nlen;
private int oldval;
private int oldlenp;
private int newval;
private int newlen;
}
private Map<Integer, SystemCallHandler> handlers = new TreeMap<>();
private int errno;
private int stackLimit = 0x800000;
private boolean error;
private List<OpenFlagMapping> openFlagMappings;
/**
* Create a system call emulation object.
*
* @param kernel the kernel
*/
public SystemCallEmulation(Kernel kernel) {
super(kernel);
this.openFlagMappings = new ArrayList<>();
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_RDONLY, OpenFlags.O_RDONLY));
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_WRONLY, OpenFlags.O_WRONLY));
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_RDWR, OpenFlags.O_RDWR));
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_APPEND, OpenFlags.O_APPEND));
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_SYNC, OpenFlags.O_SYNC));
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_CREAT, OpenFlags.O_CREAT));
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_TRUNC, OpenFlags.O_TRUNC));
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_EXCL, OpenFlags.O_EXCL));
this.openFlagMappings.add(new OpenFlagMapping(TargetOpenFlags.O_NOCTTY, OpenFlags.O_NOCTTY));
this.openFlagMappings.add(new OpenFlagMapping(0x2000, 0));
registerHandler(new SystemCallHandler(1, "exit") {
@Override
public void run(Context context) {
exit_impl(context);
}
});
registerHandler(new SystemCallHandler(3, "read") {
@Override
public void run(Context context) {
read_impl(context);
}
});
registerHandler(new SystemCallHandler(4, "write") {
@Override
public void run(Context context) {
write_impl(context);
}
});
registerHandler(new SystemCallHandler(5, "open") {
@Override
public void run(Context context) {
open_impl(context);
}
});
registerHandler(new SystemCallHandler(6, "close") {
@Override
public void run(Context context) {
close_impl(context);
}
});
registerHandler(new SystemCallHandler(7, "waitpid") {
@Override
public void run(Context context) {
waitpid_impl(context);
}
});
registerHandler(new SystemCallHandler(20, "getpid") {
@Override
public void run(Context context) {
getpid_impl(context);
}
});
registerHandler(new SystemCallHandler(24, "getuid") {
@Override
public void run(Context context) {
getuid_impl(context);
}
});
registerHandler(new SystemCallHandler(37, "kill") {
@Override
public void run(Context context) {
kill_impl(context);
}
});
registerHandler(new SystemCallHandler(42, "pipe") {
@Override
public void run(Context context) {
pipe_impl(context);
}
});
registerHandler(new SystemCallHandler(45, "brk") {
@Override
public void run(Context context) {
brk_impl(context);
}
});
registerHandler(new SystemCallHandler(47, "getgid") {
@Override
public void run(Context context) {
getgid_impl(context);
}
});
registerHandler(new SystemCallHandler(49, "geteuid") {
@Override
public void run(Context context) {
geteuid_impl(context);
}
});
registerHandler(new SystemCallHandler(50, "getegid") {
@Override
public void run(Context context) {
getegid_impl(context);
}
});
registerHandler(new SystemCallHandler(54, "ioctl") {
@Override
public void run(Context context) {
ioctl_impl(context);
}
});
registerHandler(new SystemCallHandler(64, "getppid") {
@Override
public void run(Context context) {
getppid_impl(context);
}
});
registerHandler(new SystemCallHandler(75, "setrlimit") {
@Override
public void run(Context context) {
setrlimit_impl(context);
}
});
registerHandler(new SystemCallHandler(76, "getrlimit") {
@Override
public void run(Context context) {
getrlimit_impl(context);
}
});
registerHandler(new SystemCallHandler(90, "mmap") {
@Override
public void run(Context context) {
mmap_impl(context);
}
});
registerHandler(new SystemCallHandler(91, "munmap") {
@Override
public void run(Context context) {
munmap_impl(context);
}
});
registerHandler(new SystemCallHandler(120, "clone") {
@Override
public void run(Context context) {
clone_impl(context);
}
});
registerHandler(new SystemCallHandler(122, "uname") {
@Override
public void run(Context context) {
uname_impl(context);
}
});
registerHandler(new SystemCallHandler(125, "mprotect") {
@Override
public void run(Context context) {
mprotect_impl(context);
}
});
registerHandler(new SystemCallHandler(140, "_llseek") {
@Override
public void run(Context context) {
_llseek_impl(context);
}
});
registerHandler(new SystemCallHandler(153, "_sysctl") {
@Override
public void run(Context context) {
_sysctl_impl(context);
}
});
registerHandler(new SystemCallHandler(166, "nanosleep") {
@Override
public void run(Context context) {
nanosleep_impl(context);
}
});
registerHandler(new SystemCallHandler(167, "mremap") {
@Override
public void run(Context context) {
mremap_impl(context);
}
});
registerHandler(new SystemCallHandler(188, "poll") {
@Override
public void run(Context context) {
poll_impl(context);
}
});
registerHandler(new SystemCallHandler(194, "rt_sigaction") {
@Override
public void run(Context context) {
rt_sigaction_impl(context);
}
});
registerHandler(new SystemCallHandler(195, "rt_sigprocmask") {
@Override
public void run(Context context) {
rt_sigprocmask_impl(context);
}
});
registerHandler(new SystemCallHandler(199, "rt_sigsuspend") {
@Override
public void run(Context context) {
rt_sigsuspend_impl(context);
}
});
registerHandler(new SystemCallHandler(215, "fstat64") {
@Override
public void run(Context context) {
fstat64_impl(context);
}
});
registerHandler(new SystemCallHandler(246, "exit_group") {
@Override
public void run(Context context) {
exit_group_impl(context);
}
});
}
/**
* Do the specified system call.
*
* @param callNum the number of the system call
* @param context the context
*/
public void doSystemCall(int callNum, Context context) {
int systemCallIndex = callNum - 4000;
if (!findAndCallSystemCallHandler(systemCallIndex, context)) {
throw new RuntimeException(String.format("ctx-%d: system call %d (%d) not implemented", context.getId(), callNum, systemCallIndex));
}
}
/**
* Check if there is any system call error for the specified context.
*
* @param context the context
* @return a value indicating whether there is any system call error for the specified context
*/
private boolean checkSystemCallError(Context context) {
if (context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_V0) != -1) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
return false;
} else {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, errno);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 1);
return true;
}
}
/**
* Find and call the system call handler for the specified system call index and context.
*
* @param systemCallIndex the system call index
* @param context the context
* @return a value indicating whether there is a registered system call handler matching the specified system call index
*/
private boolean findAndCallSystemCallHandler(int systemCallIndex, Context context) {
if (handlers.containsKey(systemCallIndex)) {
SystemCallHandler systemCallHandler = handlers.get(systemCallIndex);
systemCallHandler.run(context);
this.getBlockingEventDispatcher().dispatch(new SystemCallExecutedEvent(context, systemCallHandler.getName()));
// Logger.infof(Logger.SYSTEM_CALL, "%s 0x%08x: system call %s (a0=0x%08x, a1=0x%08x, a2=0x%08x); %s", context.getThread().getName(), context.getRegisterFile().getPc(), systemCallHandler.getName(),
// context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0),
// context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1),
// context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2),
// systemCallHandler.isError() ? String.format("errorno=0x%08x", errno) : String.format("ret=0x%08x", context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_V0)));
// System.out.printf("%s\n", context.getRegisterFile().dump());
context.getKernel().processSystemEvents();
context.getKernel().processSignals();
return true;
}
return false;
}
/**
* Register the specified system call handler.
*
* @param handler the system call handler to be registered
*/
private void registerHandler(SystemCallHandler handler) {
handlers.put(handler.getIndex(), handler);
}
/**
* exit_group implementation.
*
* @param context the context
*/
private void exit_group_impl(Context context) {
context.finish();
}
/**
* Get the file descriptor by the specified file descriptor number.
*
* @param fd the file descriptor number
* @return the file descriptor
*/
public static FileDescriptor getFD(int fd) {
try {
return new FileInputStream("/proc/self/fd/" + fd).getFD();
} catch (IOException e) {
return null;
}
}
/**
* fstat64 implementation.
*
* @param context the context
*/
private void fstat64_impl(Context context) {
int fd = context.getProcess().translateFileDescriptor(context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0));
int bufAddr = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
FileStat fstat = PosixUtil.current().fstat(fd);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
error = checkSystemCallError(context);
if (!error) {
int sizeOfDataToWrite = 104;
byte[] dataToWrite = new byte[sizeOfDataToWrite];
ByteBuffer bb = ByteBuffer.wrap(dataToWrite).order(context.getProcess().isLittleEndian() ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
bb.putInt(0, (int) fstat.dev());
bb.putInt(16, (int) fstat.ino());
bb.putInt(24, fstat.mode());
bb.putInt(28, fstat.nlink());
bb.putInt(32, fstat.uid());
bb.putInt(36, fstat.gid());
bb.putInt(40, (int) fstat.rdev());
bb.putLong(56, fstat.st_size());
bb.putInt(64, (int) fstat.atime());
bb.putInt(72, (int) fstat.mtime());
bb.putInt(80, (int) fstat.ctime());
bb.putInt(88, (int) fstat.blockSize());
bb.putLong(96, fstat.blocks());
context.getProcess().getMemory().writeBlock(bufAddr, sizeOfDataToWrite, dataToWrite);
}
}
/**
* rt_sigsuspend implementation.
*
* @param context the context
*/
private void rt_sigsuspend_impl(Context context) {
int pmask = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
if (pmask == 0) {
throw new IllegalArgumentException("sigsuspend with mask being null");
}
try {
context.getSignalMasks().setBackup((SignalMask) context.getSignalMasks().getBlocked().clone());
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
context.getSignalMasks().getBlocked().loadFrom(context.getProcess().getMemory(), pmask);
context.suspend();
SignalSuspendEvent e = new SignalSuspendEvent(context);
context.getKernel().scheduleSystemEvent(e);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* rt_sigprocmask implementation.
*
* @param context the context
*/
private void rt_sigprocmask_impl(Context context) {
int how = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int pset = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int poset = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2);
if (poset != 0) {
context.getSignalMasks().getBlocked().saveTo(context.getProcess().getMemory(), poset);
}
if (pset != 0) {
SignalMask set = new SignalMask();
set.loadFrom(context.getProcess().getMemory(), pset);
if (how == 1) {
for (int i = 1; i <= Kernel.MAX_SIGNAL; i++) {
if (set.contains(i)) {
context.getSignalMasks().getBlocked().set(i);
}
}
} else if (how == 2) {
for (int i = 1; i <= Kernel.MAX_SIGNAL; i++) {
if (set.contains(i)) {
context.getSignalMasks().getBlocked().clear(i);
}
}
} else if (how == 3) {
try {
context.getSignalMasks().setBlocked((SignalMask) set.clone());
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* rt_sigaction implementation.
*
* @param context the context
*/
private void rt_sigaction_impl(Context context) {
int signum = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int pact = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int poact = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2);
if (poact != 0) {
context.getKernel().getSignalActions().get(signum - 1).saveTo(context.getProcess().getMemory(), poact);
}
if (pact != 0) {
context.getKernel().getSignalActions().get(signum - 1).loadFrom(context.getProcess().getMemory(), pact);
}
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* poll implementation.
*
* @param context the context
*/
private void poll_impl(Context context) {
int pufds = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int nfds = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int timeout = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2);
if (nfds < 1) {
throw new IllegalArgumentException("system call poll: nfds < 1");
}
for (int i = 0; i < nfds; i++, pufds += 8) {
int fd = context.getProcess().getMemory().readWord(pufds);
short events = context.getProcess().getMemory().readHalfWord(pufds + 4);
if (events != 1) {
throw new IllegalArgumentException("system call poll: ufds.events != POLLIN");
}
PollEvent e = new PollEvent(context);
e.getTimeCriterion().setWhen(NativeSystemCalls.clock(context.getKernel().getCurrentCycle()) + timeout * NativeSystemCalls.CLOCKS_PER_SEC / 1000);
e.getWaitForFileDescriptorCriterion().setBuffer(context.getKernel().getReadBuffer(fd));
if (e.getWaitForFileDescriptorCriterion().getBuffer() == null) {
throw new IllegalArgumentException("system call poll: fd does not belong to a pipe read buffer");
}
e.getWaitForFileDescriptorCriterion().setPufds(pufds);
context.getKernel().scheduleSystemEvent(e);
}
context.suspend();
}
/**
* nanosleep implementation.
*
* @param context the context
*/
private void nanosleep_impl(Context context) {
int preq = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int sec = context.getProcess().getMemory().readWord(preq);
int nsec = context.getProcess().getMemory().readWord(preq + 4);
int total = (int) (sec * NativeSystemCalls.CLOCKS_PER_SEC + nsec / 1e9 * NativeSystemCalls.CLOCKS_PER_SEC);
ResumeEvent e = new ResumeEvent(context);
e.getTimeCriterion().setWhen(NativeSystemCalls.clock(context.getKernel().getCurrentCycle()) + total);
context.getKernel().scheduleSystemEvent(e);
context.suspend();
}
/**
* mremap implementation.
*
* @param context the context
*/
private void mremap_impl(Context context) {
int oldAddr = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int oldSize = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int newSize = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2);
int start = context.getProcess().getMemory().remap(oldAddr, oldSize, newSize);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, start);
error = checkSystemCallError(context);
}
/**
* _sysctl implementation.
*
* @param context the context
*/
private void _sysctl_impl(Context context) {
byte[] buf = context.getProcess().getMemory().readBlock(context.getRegisterFile().getGpr(4), 4 * 6);
ByteBuffer bb = ByteBuffer.wrap(buf).order(context.getProcess().isLittleEndian() ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
SysctrlArgs args = new SysctrlArgs();
args.name = bb.getInt();
args.nlen = bb.getInt();
args.oldval = bb.getInt();
args.oldlenp = bb.getInt();
args.newval = bb.getInt();
args.newlen = bb.getInt();
byte[] buf2 = context.getProcess().getMemory().readBlock(args.name, 4 * 10);
ByteBuffer bb2 = ByteBuffer.wrap(buf2).order(context.getProcess().isLittleEndian() ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
int[] name = new int[10];
for (int i = 0; i < name.length; i++) {
name[i] = bb2.getInt();
}
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
name[0] = 0; //TODO: hack for the moment
if (name[0] != 0) {
throw new RuntimeException("system call sysctl still not implemented for name[0] != 0");
}
}
/**
* _llseek implementation.
*
* @param context the context
*/
private void _llseek_impl(Context context) {
int fd = context.getProcess().translateFileDescriptor(context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0));
int offset = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int whence = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2);
int ret = NativeSystemCalls.LIBC.lseek(fd, offset, whence);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, ret);
error = checkSystemCallError(context);
}
/**
* mprotect implementation.
*
* @param context the context
*/
private void mprotect_impl(Context context) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* uname implementation.
*
* @param context the context
*/
private void uname_impl(Context context) {
Utsname un = new Utsname();
un.sysname = "Linux";
un.nodename = "sim";
un.release = "2.6";
un.version = "Tue Apr 5 12:21:57 UTC 2005";
un.machine = "mips";
byte[] un_buf = un.getBytes(context.getProcess().isLittleEndian());
context.getProcess().getMemory().writeBlock(context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0), un_buf.length, un_buf);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* clone implementation.
*
* @param context the context
*/
private void clone_impl(Context context) {
int cloneFlags = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int newSp = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
Context newContext;
try {
newContext = new Context(context, (ArchitecturalRegisterFile) context.getRegisterFile().clone(), cloneFlags & 0xff);
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
if (!context.getKernel().map(newContext, candidateThreadId -> true)) {
throw new RuntimeException();
}
context.getKernel().getContexts().add(newContext);
newContext.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_SP, newSp);
newContext.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
newContext.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, newContext.getProcessId());
}
/**
* munmap implementation.
*
* @param context the context
*/
private void munmap_impl(Context context) {
int start = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int length = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
context.getProcess().getMemory().unmap(start, length);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* mmap implementation.
*
* @param context the context
*/
private void mmap_impl(Context context) {
int start = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int length = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int fd = context.getProcess().getMemory().readWord(context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_SP) + 16);
if (fd != -1) {
throw new IllegalArgumentException("system call mmap: system call is only supported with fd=-1");
}
if (start == 0) {
start = context.getProcess().getHeapTop();
}
start = context.getProcess().getMemory().map(start, length);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, start);
}
/**
* getrlimit implementation.
*
* @param context the context
*/
private void getrlimit_impl(Context context) {
int prlimit = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
if (context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0) != 3) {
throw new RuntimeException();
}
context.getProcess().getMemory().writeWord(prlimit, stackLimit);
context.getProcess().getMemory().writeWord(prlimit + 4, 0xffffffff);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* setrlimit implementation.
*
* @param context the context
*/
private void setrlimit_impl(Context context) {
if (context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0) != 3) {
throw new RuntimeException();
}
stackLimit = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* getppid implementation.
*
* @param context the context
*/
private void getppid_impl(Context context) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, context.getParentProcessId());
error = checkSystemCallError(context);
}
/**
* ioctl implementation.
*
* @param context the context
*/
private void ioctl_impl(Context context) {
byte[] buf = new byte[128];
if (context.getRegisterFile().getGpr(6) != 0) {
buf = context.getProcess().getMemory().readBlock(context.getRegisterFile().getGpr(6), 128);
}
int fd = context.getProcess().translateFileDescriptor(context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0));
if (fd < 3) {
context.getRegisterFile().setGpr(2, NativeSystemCalls.LIBC.ioctl(fd, context.getRegisterFile().getGpr(5), buf)); //TODO: retrive errno value from libc call
error = checkSystemCallError(context);
if (context.getRegisterFile().getGpr(6) != 0) {
context.getProcess().getMemory().writeBlock(context.getRegisterFile().getGpr(6), 128, buf);
}
} else {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
}
/**
* getegid implementation.
*
* @param context the context
*/
private void getegid_impl(Context context) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, context.getEffectiveGroupId());
error = checkSystemCallError(context);
}
/**
* geteuid implementation.
*
* @param context the context
*/
private void geteuid_impl(Context context) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, context.getEffectiveUserId());
error = checkSystemCallError(context);
}
/**
* getgid implementation.
*
* @param context the context
*/
private void getgid_impl(Context context) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, context.getGroupId());
error = checkSystemCallError(context);
}
/**
* brk implementation.
*
* @param context the context
*/
private void brk_impl(Context context) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
}
/**
* pipe implementation.
*
* @param context the context
*/
private void pipe_impl(Context context) {
int[] fileDescriptors = new int[2];
context.getKernel().createPipe(fileDescriptors);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, fileDescriptors[0]);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V1, fileDescriptors[1]);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
// System.out.printf("\tpipe created with fd={%d, %d}\n", fd[0], fd[1]);
}
/**
* kill implementation.
*
* @param context the context
*/
private void kill_impl(Context context) {
int pid = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int sig = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
if (pid < 1) {
throw new RuntimeException();
}
Context destContext = context.getKernel().getContextFromProcessId(pid);
if (destContext == null) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, ESRCH);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, -1);
return;
}
destContext.getSignalMasks().getPending().set(sig);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, 0);
// System.out.printf("\t%s: sending signal %d to %s (pid=%d)\n", context.getThread().getName(), sig, destContext.getThread().getName(), pid);
}
/**
* getuid implementation.
*
* @param context the context
*/
private void getuid_impl(Context context) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, context.getUserId());
error = checkSystemCallError(context);
}
/**
* getpid implementation.
*
* @param context the context
*/
private void getpid_impl(Context context) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, context.getProcessId());
error = checkSystemCallError(context);
}
/**
* waitpid implementation.
*
* @param context the context
*/
private void waitpid_impl(Context context) {
int pid = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int pstatus = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
if (pid < 1) {
throw new RuntimeException();
}
if (context.getKernel().getContextFromProcessId(pid) == null) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, ECHILD);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, -1);
return;
}
WaitEvent e = new WaitEvent(context, pid);
context.getKernel().scheduleSystemEvent(e);
context.suspend();
if (pstatus != 0) {
throw new RuntimeException();
}
}
/**
* close implementation.
*
* @param context the context
*/
private void close_impl(Context context) {
int fd = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
if (fd == 0 || fd == 1 || fd == 2) {
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_A3, 0);
return;
}
int ret = NativeSystemCalls.LIBC.close(fd);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, ret);
error = checkSystemCallError(context);
}
/**
* open implementation.
*
* @param context the context
*/
private void open_impl(Context context) {
int addr = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0);
int tgtFlags = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int mode = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2);
int hostFlags = 0;
for (OpenFlagMapping mapping : this.openFlagMappings) {
if ((tgtFlags & mapping.getTargetFlag()) != 0) {
tgtFlags &= ~mapping.getTargetFlag();
hostFlags |= mapping.getHostFlag();
}
}
if (tgtFlags != 0) {
Logger.fatalf(Logger.SYSTEM_CALL, "system call open: cannot decode flags 0x%08x", context.getCycleAccurateEventQueue().getCurrentCycle(), tgtFlags);
}
String path = context.getProcess().getMemory().readString(addr, MAX_BUFFER_SIZE);
int ret = NativeSystemCalls.LIBC.open(path, hostFlags, mode);
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, ret);
error = checkSystemCallError(context);
}
/**
* write implementation.
*
* @param context the context
*/
private void write_impl(Context context) {
int fd = context.getProcess().translateFileDescriptor(context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0));
int bufAddr = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int count = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2);
byte[] buf = context.getProcess().getMemory().readBlock(bufAddr, count);
int ret;
CircularByteBuffer buffer = context.getKernel().getWriteBuffer(fd);
if (buffer != null) {
buffer.write(buf, 0, count);
ret = count;
} else {
ret = NativeSystemCalls.LIBC.write(fd, buf, count);
}
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, ret);
error = checkSystemCallError(context);
// System.out.printf("\tsystem call write: %d bytes written to fd=%d\n", ret, fd);
}
/**
* read implementation.
*
* @param context the context
*/
private void read_impl(Context context) {
int readMaxSize = 1 << 25;
int fd = context.getProcess().translateFileDescriptor(context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A0));
int bufAddr = context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A1);
int count = Math.min(readMaxSize, context.getRegisterFile().getGpr(ArchitecturalRegisterFile.REGISTER_A2));
int ret;
byte[] buf;
CircularByteBuffer buffer = context.getKernel().getReadBuffer(fd);
if (buffer != null) {
if (buffer.isEmpty()) {
ReadEvent e = new ReadEvent(context);
e.getWaitForFileDescriptorCriterion().setBuffer(buffer);
e.getWaitForFileDescriptorCriterion().setAddress(bufAddr);
e.getWaitForFileDescriptorCriterion().setSize(count);
context.getKernel().scheduleSystemEvent(e);
context.suspend();
return;
} else {
buf = new byte[count];
ret = buffer.read(buf, 0, count);
}
} else {
buf = new byte[count];
ret = NativeSystemCalls.LIBC.read(fd, buf, count);
}
if (ret >= readMaxSize) {
throw new RuntimeException();
}
context.getRegisterFile().setGpr(ArchitecturalRegisterFile.REGISTER_V0, ret);
this.error = checkSystemCallError(context);
context.getProcess().getMemory().writeBlock(bufAddr, ret, buf);
// System.out.printf("\tsystem call read: %d bytes read from fd=%d\n", ret, fd);
}
/**
* exit implementation.
*
* @param context the context
*/
private void exit_impl(Context context) {
context.finish();
}
/**
* Get the name of the system call emulation object.
*
* @return the name of the system call emulation object
*/
@Override
public String getName() {
return "systemCallEmulation";
}
/**
* EPERM.
*/
public static final int EPERM = 1;
/**
* ENOENT.
*/
public static final int ENOENT = 2;
/**
* ESRCH.
*/
public static final int ESRCH = 3;
/**
* EINTR.
*/
public static final int EINTR = 4;
/**
* EIO.
*/
public static final int EIO = 5;
/**
* ENXIO.
*/
public static final int ENXIO = 6;
/**
* E2BIG.
*/
public static final int E2BIG = 7;
/**
* ENOEXEC.
*/
public static final int ENOEXEC = 8;
/**
* EBADF.
*/
public static final int EBADF = 9;
/**
* ECHILD.
*/
public static final int ECHILD = 10;
/**
* EAGAIN.
*/
public static final int EAGAIN = 11;
/**
* ENOMEM.
*/
public static final int ENOMEM = 12;
/**
* EACCES.
*/
public static final int EACCES = 13;
/**
* EFAULT.
*/
public static final int EFAULT = 14;
/**
* ENOTBLK.
*/
public static final int ENOTBLK = 15;
/**
* EBUSY.
*/
public static final int EBUSY = 16;
/**
* EEXIST.
*/
public static final int EEXIST = 17;
/**
* EXDEV.
*/
public static final int EXDEV = 18;
/**
* ENODEV.
*/
public static final int ENODEV = 19;
/**
* ENOTDIR.
*/
public static final int ENOTDIR = 20;
/**
* EISDIR.
*/
public static final int EISDIR = 21;
/**
* EINVAL.
*/
public static final int EINVAL = 22;
/**
* ENFILE.
*/
public static final int ENFILE = 23;
/**
* EMFILE.
*/
public static final int EMFILE = 24;
/**
* ENOTTY.
*/
public static final int ENOTTY = 25;
/**
* ETXTBSY.
*/
public static final int ETXTBSY = 26;
/**
* EFBIG.
*/
public static final int EFBIG = 27;
/**
* ENOSPC.
*/
public static final int ENOSPC = 28;
/**
* ESPIPE.
*/
public static final int ESPIPE = 29;
/**
* EROFS.
*/
public static final int EROFS = 30;
/**
* EMLINK.
*/
public static final int EMLINK = 31;
/**
* EPIPE.
*/
public static final int EPIPE = 32;
/**
* EDOM.
*/
public static final int EDOM = 33;
/**
* ERANGE.
*/
public static final int ERANGE = 34;
/**
* Maximum buffer size.
*/
private static final int MAX_BUFFER_SIZE = 1024;
}