public static void DumpUserBuf(Thread current, UserPtr writeBuf, int size) { var buf = new byte[(size + 3) / 4]; var buf_ref = new ByteBufferRef(buf); writeBuf.Read(current, buf, size); DumpBuf(new Pointer(buf_ref.Location), size); }
public static int DoFutex(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int op, int val, UserPtr timeoutPtr, UserPtr uaddr2, uint val3) { var cmd = op & FUTEX_CMD_MASK; var flags = ToFlags(op, cmd); timespec ts; ts.tv_sec = ts.tv_nsec = 0; // Don't care about shared mutex if ((flags & FLAGS_SHARED) != 0) { return DoFutexShared(current, ref regs, uaddr, op, val, timeoutPtr, uaddr2, val3); } bool hasTimeout = timeoutPtr != UserPtr.Zero; if (hasTimeout && timeoutPtr.Read(current, out ts) != 0) return -ErrorCode.EFAULT; switch (cmd) { case FUTEX_WAIT: return Wait(current, ref regs, uaddr, flags, val, hasTimeout, ts, FUTEX_BITSET_MATCH_ANY); case FUTEX_WAIT_BITSET: return Wait(current, ref regs, uaddr, flags, val, hasTimeout, ts, val3); case FUTEX_WAKE: return Wake(current, uaddr, flags, val, FUTEX_BITSET_MATCH_ANY); case FUTEX_WAKE_BITSET: return Wake(current, uaddr, flags, val, val3); default: Arch.Console.Write("futex: unknown primitives "); Arch.Console.Write(cmd); Arch.Console.WriteLine(); return -ErrorCode.ENOSYS; } }
internal static int AshmemIoctl(GenericINode generic_inode, Thread current, uint cmd, UserPtr arg1) { Contract.Requires(Globals.LinuxIPCBuffer.Length >= AshmemINode.ASHMEM_PIN_SIZE); int ret = 0; switch (cmd) { case AshmemINode.ASHMEM_SET_NAME: arg1.ReadString(current, Globals.LinuxIPCBuffer); break; case AshmemINode.ASHMEM_PIN: case AshmemINode.ASHMEM_UNPIN: if (arg1.Read(current, Globals.LinuxIPCBuffer, AshmemINode.ASHMEM_PIN_SIZE) != 0) ret = -ErrorCode.EFAULT; break; case AshmemINode.ASHMEM_GET_NAME: case AshmemINode.ASHMEM_SET_SIZE: case AshmemINode.ASHMEM_GET_SIZE: case AshmemINode.ASHMEM_SET_PROT_MASK: case AshmemINode.ASHMEM_GET_PROT_MASK: case AshmemINode.ASHMEM_GET_PIN_STATUS: case AshmemINode.ASHMEM_PURGE_ALL_CACHES: break; default: ret = -ErrorCode.ENOSYS; break; } if (ret < 0) return ret; var linux_fd = generic_inode.LinuxFd; ret = Arch.IPCStubs.linux_sys_vfs_ashmem_ioctl(current.Parent.helperPid, linux_fd, cmd, arg1.Value.ToInt32()); if (ret < 0) return ret; // unmarshal if necessary if (cmd == AshmemINode.ASHMEM_GET_NAME) { var length = Util.Strnlen(Globals.LinuxIPCBuffer, AshmemINode.ASHMEM_NAME_LEN); // include terminator if (length < AshmemINode.ASHMEM_NAME_LEN) length++; var buf = Globals.LinuxIPCBuffer.Slice(0, length); if (arg1.Write(current, Globals.LinuxIPCBuffer) != 0) return -ErrorCode.EFAULT; } return ret; }
private static void DumpUserBuf(Thread current, UserPtr writeBuf, int size) { var buf = new byte[(size + 3) / 4]; writeBuf.Read(current, buf, size); var buf_ref = new ByteBufferRef(buf); DumpBuf(new Pointer(buf_ref.Location), size); }
private static int BindOrConnect(int type, Thread current, ref Arch.ExceptionRegisters regs, int sockfd, UserPtr sockaddr, int addrlen) { Contract.Requires(type == SYS_BIND || type == SYS_CONNECT); var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) { return(-ErrorCode.EBADF); } if (file.inode.kind != GenericINode.INodeKind.SocketINodeKind) { return(-ErrorCode.ENOTSOCK); } if (addrlen > Globals.LinuxIPCBuffer.Length) { return(-ErrorCode.EINVAL); } var buf = Globals.AllocateAlignedCompletionBuffer(addrlen); if (!buf.isValid) { return(-ErrorCode.ENOMEM); } var completion = new BridgeCompletion(current, buf); if (sockaddr.Read(current, buf, addrlen) != 0) { completion.Dispose(); return(-ErrorCode.EFAULT); } if (type == SYS_BIND) { Arch.IPCStubs.BindAsync(proc.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), file.inode.LinuxFd, addrlen); } else if (type == SYS_CONNECT) { Arch.IPCStubs.ConnectAsync(proc.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), file.inode.LinuxFd, addrlen); } Globals.CompletionQueue.Enqueue(completion); current.SaveState(ref regs); current.AsyncReturn = true; return(0); }
private static int Sendto(Thread current, int sockfd, UserPtr userBuf, int len, int flags, UserPtr sockaddr, int addrlen) { var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) { return(-ErrorCode.EBADF); } var buf = Globals.LinuxIPCBuffer; if (len < 0 || addrlen < 0) { return(-ErrorCode.EINVAL); } if (len + addrlen > buf.Length) { return(-ErrorCode.ENOMEM); } if (sockaddr == UserPtr.Zero && addrlen != 0) { return(-ErrorCode.EINVAL); } Contract.Assert(buf.Length >= len + addrlen); if (userBuf.Read(current, buf, len) != 0) { return(-ErrorCode.EFAULT); } var old_buf_len = buf.Length; var sockaddr_buf = buf.Slice(len, buf.Length - len); // Post-condition of ByteBufferRef#ctor and slice Contract.Assume(buf.Length == old_buf_len); Contract.Assume(sockaddr_buf.Length == buf.Length - len); Contract.Assert(buf.Length - len >= addrlen); if (sockaddr != UserPtr.Zero && sockaddr.Read(current, sockaddr_buf, addrlen) != 0) { return(-ErrorCode.EFAULT); } return(Arch.IPCStubs.Sendto(proc.helperPid, file.inode.LinuxFd, len, flags, addrlen)); }
internal int AddUserFdList(Thread current, UserPtr fdlist, int maxfds, short event_type) { if (fdlist == UserPtr.Zero) return 0; var buf = new byte[(maxfds + 7) / 8]; if (fdlist.Read(current, buf) != 0) return -ErrorCode.EFAULT; var vec = new FixedSizeBitVector(maxfds, buf); var ret = AddFdList(current, vec, event_type); return ret; }
// XXX: Move to some places public static void DumpStackTrace(Thread current, UserPtr ebp) { int eip; int new_ebp; while (ebp != UserPtr.Zero) { Arch.Console.Write("EIP:"); if ((ebp + sizeof(int)).Read(current, out eip) != 0) return; Arch.Console.Write(eip); Arch.Console.WriteLine(); if (ebp.Read(current, out new_ebp) != 0) return; ebp = new UserPtr(new_ebp); } }
public static int SetThreadArea(Thread current, UserPtr userDescriptor) { var info = new userdesc(); if (userDescriptor.Read(current, out info) != 0) { return(-ErrorCode.EFAULT); } var ret = NativeMethods.l4api_set_thread_area(current.impl._value.thread, current.TLSArray, -1, ref info, 1); if (userDescriptor.Write(current, info) != 0) { return(-ErrorCode.EFAULT); } return(ret); }
private static int Send(Thread current, int cap_idx, UserPtr userBuf, uint size) { if (!current.Parent.Space.VerifyRead(userBuf, size)) { return(-ErrorCode.EFAULT); } var cap_ref = current.VBinderState.Find(current, cap_idx); if (cap_ref == null) { return(-ErrorCode.EINVAL); } var blob = Globals.AllocateAlignedCompletionBuffer((int)size); if (!blob.isValid) { return(-ErrorCode.ENOMEM); } if (userBuf.Read(current, blob, (int)size) != 0) { return(-ErrorCode.EFAULT); } var targetThread = cap_ref.def.parent; // Object invariant of thread Contract.Assume(targetThread.VBinderState.Owner == targetThread); var msg = new VBinderMessage(current, targetThread, cap_ref.def.label, blob, (int)size); if (targetThread.VBinderState.Completion != null) { HandleAsyncCall(targetThread, msg); } else { Contract.Assert(msg.GhostTarget == targetThread); targetThread.VBinderState.Enqueue(msg); } return((int)size); }
public const int SYS_SENDMMSG = 20; /* sys_sendmmsg(2) */ public static int Poll(Thread current, ref Arch.ExceptionRegisters regs, UserPtr fds, int nfds, int timeout) { if (nfds < 0) { return(-ErrorCode.EINVAL); } var pollfd_size = pollfd.Size * nfds; var buf = Globals.AllocateAlignedCompletionBuffer(pollfd_size); if (!buf.isValid) { return(-ErrorCode.ENOMEM); } var poll_entry = new PollCompletion(current, fds, nfds, buf); if (fds.Read(current, buf, pollfd_size) != 0) { poll_entry.Dispose(); return(-ErrorCode.EFAULT); } Contract.Assert(buf.Length >= pollfd_size); if (!TranslateToLinuxFd(current, poll_entry, buf)) { poll_entry.Dispose(); return(-ErrorCode.EBADF); } var ret = Arch.IPCStubs.PollAsync(current.Parent.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), nfds, timeout); if (ret < 0) { poll_entry.Dispose(); return(ret); } Globals.CompletionQueue.Enqueue(poll_entry); current.SaveState(ref regs); current.AsyncReturn = true; return(0); }
private static int Getsockopt(Thread current, ref Arch.ExceptionRegisters regs, int sockfd, int level, int optname, UserPtr optval, UserPtr p_optlen) { var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) { return(-ErrorCode.EBADF); } if (file.inode.kind != GenericINode.INodeKind.SocketINodeKind) { return(-ErrorCode.ENOTSOCK); } uint optlen = 0; if (p_optlen.Read(current, out optlen) != 0) { return(-ErrorCode.EFAULT); } if (optlen > Globals.LinuxIPCBuffer.Length) { return(-ErrorCode.EINVAL); } var buf = Globals.AllocateAlignedCompletionBuffer((int)optlen); if (!buf.isValid) { return(-ErrorCode.ENOMEM); } var completion = new GetSockParamCompletion(current, optval, p_optlen, buf); Arch.IPCStubs.GetSockoptAsync(proc.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), file.inode.LinuxFd, level, optname, (int)optlen); Globals.CompletionQueue.Enqueue(completion); current.SaveState(ref regs); current.AsyncReturn = true; return(0); }
public static int DoFutex(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int op, int val, UserPtr timeoutPtr, UserPtr uaddr2, uint val3) { var cmd = op & FUTEX_CMD_MASK; var flags = ToFlags(op, cmd); timespec ts; ts.tv_sec = ts.tv_nsec = 0; // Don't care about shared mutex if ((flags & FLAGS_SHARED) != 0) { return(DoFutexShared(current, ref regs, uaddr, op, val, timeoutPtr, uaddr2, val3)); } bool hasTimeout = timeoutPtr != UserPtr.Zero; if (hasTimeout && timeoutPtr.Read(current, out ts) != 0) { return(-ErrorCode.EFAULT); } switch (cmd) { case FUTEX_WAIT: return(Wait(current, ref regs, uaddr, flags, val, hasTimeout, ts, FUTEX_BITSET_MATCH_ANY)); case FUTEX_WAIT_BITSET: return(Wait(current, ref regs, uaddr, flags, val, hasTimeout, ts, val3)); case FUTEX_WAKE: return(Wake(current, uaddr, flags, val, FUTEX_BITSET_MATCH_ANY)); case FUTEX_WAKE_BITSET: return(Wake(current, uaddr, flags, val, val3)); default: Arch.Console.Write("futex: unknown primitives "); Arch.Console.Write(cmd); Arch.Console.WriteLine(); return(-ErrorCode.ENOSYS); } }
internal int AddUserFdList(Thread current, UserPtr fdlist, int maxfds, short event_type) { if (fdlist == UserPtr.Zero) { return(0); } var buf = new byte[(maxfds + 7) / 8]; if (fdlist.Read(current, buf) != 0) { return(-ErrorCode.EFAULT); } var vec = new FixedSizeBitVector(maxfds, buf); var ret = AddFdList(current, vec, event_type); return(ret); }
public static int Nanosleep(Thread current, ref Arch.ExceptionRegisters regs, UserPtr rqtp, UserPtr rmtp) { timespec ts; timespec trem; trem.tv_sec = 0; trem.tv_nsec = 0; if (rqtp.Read(current, out ts) != 0 || rmtp.Write(current, ref trem) != 0) { return(-ErrorCode.EFAULT); } Globals.TimeoutQueue.Enqueue(ts.ToMilliseconds(), current); var c = new SleepCompletion(current); Globals.CompletionQueue.Enqueue(c); current.SaveState(ref regs); current.AsyncReturn = true; return(0); }
// XXX: Move to some places public static void DumpStackTrace(Thread current, UserPtr ebp) { int eip; int new_ebp; while (ebp != UserPtr.Zero) { Arch.Console.Write("EIP:"); if ((ebp + sizeof(int)).Read(current, out eip) != 0) { return; } Arch.Console.Write(eip); Arch.Console.WriteLine(); if (ebp.Read(current, out new_ebp) != 0) { return; } ebp = new UserPtr(new_ebp); } }
private static int RecvFrom(Thread current, int sockfd, UserPtr userBuf, int len, int flags, UserPtr sockaddr, UserPtr p_addrlen) { var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) { return(-ErrorCode.EBADF); } int addrlen; if (p_addrlen.Read(current, out addrlen) != 0) { return(-ErrorCode.EFAULT); } var buf = Globals.LinuxIPCBuffer; if (len + addrlen > buf.Length) { return(-ErrorCode.ENOMEM); } var ret = Arch.IPCStubs.Recvfrom(proc.helperPid, file.inode.LinuxFd, len, flags, ref addrlen); if (ret < 0) { return(ret); } var left = userBuf.Write(current, new Pointer(buf.Location), ret); if (sockaddr.Write(current, new Pointer(buf.Location + ret - left), addrlen) != 0) { return(-ErrorCode.EFAULT); } return(ret - left); }
private int MarshalDataSegments(int size, ref UserPtr data, int offset) { Contract.Requires(size >= 0); Contract.Ensures(ReadCursor == Contract.OldValue(ReadCursor)); if (size == 0) { return(0); } if (size > buf.Length - WriteCursor) { return(-ErrorCode.ENOMEM); } var b = buf.Slice(WriteCursor, size); // Post condition for ByteBufferRef Contract.Assume(b.Length == size); var r = data.Read(current, b, size); if (r != 0) { return(-ErrorCode.EFAULT); } data = new UserPtr((uint)WriteCursor); WriteCursor += size; // Add patch entry if (CurrentPatchEntry >= kPatchTableSize) { return(-ErrorCode.ENOMEM); } patchTable[CurrentPatchEntry++] = ReadCursor + offset; return(0); }
internal int Write(Thread current, ref Arch.ExceptionRegisters regs, UserPtr userBuf, int len, uint pos, File file) { var buf = Globals.AllocateAlignedCompletionBuffer(len); if (!buf.isValid) { return(-ErrorCode.ENOMEM); } var l = userBuf.Read(current, buf, len); var bytesToBeWritten = len - l; var ret = Write(current, ref regs, ref buf, bytesToBeWritten, pos, file); // Buffer hasn't been taken by write(), free it here if (buf.isValid) { Globals.CompletionQueueAllocator.FreePages(new Pointer(buf.Location), buf.Length >> Arch.ArchDefinition.PageShift); } return(ret); }
private static int Wait(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int flags, int val, bool hasTimeout, timespec ts, uint bitset) { int old_val; if (uaddr.Read(current, out old_val) != 0) { return(-ErrorCode.EFAULT); } if (old_val != val) { return(-ErrorCode.EWOULDBLOCK); } //Arch.Console.Write("wait: addr="); //Arch.Console.Write(uaddr.Value.ToUInt32()); //Arch.Console.Write(" thr="); //Arch.Console.Write(current.Tid); //Arch.Console.WriteLine(); TimerQueueNode node; var futex_entry = new FutexCompletionEntry(current, uaddr, bitset); Globals.FutexLists.InsertAtTail(futex_entry); if (hasTimeout) { node = Globals.TimeoutQueue.Enqueue(ts.ToMilliseconds(), current); futex_entry.timeoutNode = node; } Globals.CompletionQueue.Enqueue(futex_entry); current.SaveState(ref regs); current.AsyncReturn = true; return(0); }
// Forward the futex request to Linux helper private static int DoFutexShared(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int op, int val, UserPtr timeoutPtr, UserPtr uaddr2, uint val3) { // Some local test var cmd = op & FUTEX_CMD_MASK; timespec ts = new timespec(); bool hasTimeout = timeoutPtr != UserPtr.Zero; if (hasTimeout && timeoutPtr.Read(current, out ts) != 0) return -ErrorCode.EFAULT; if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_BITSET) { int old_val; if (uaddr.Read(current, out old_val) != 0) return -ErrorCode.EFAULT; if (old_val != val) return -ErrorCode.EWOULDBLOCK; var bitset = cmd == FUTEX_WAIT ? FUTEX_BITSET_MATCH_ANY : val3; var shadowAddr = FindShadowAddr(current, uaddr); if (shadowAddr == Pointer.Zero) { Arch.Console.WriteLine("FutexShared: Don't know how to deal with shared_wait"); return 0; } var futex_entry = new FutexCompletionEntry(current, uaddr, bitset); Arch.IPCStubs.linux_sys_futex_wait(current.Parent.helperPid, current.impl._value.thread._value, op, shadowAddr, val, ts, bitset); Globals.CompletionQueue.Enqueue(futex_entry); current.SaveState(ref regs); current.AsyncReturn = true; return 0; } else if (cmd == FUTEX_WAKE || cmd == FUTEX_WAKE_BITSET) { var bitset = cmd == FUTEX_WAKE ? FUTEX_BITSET_MATCH_ANY : val3; if (bitset == 0) return -ErrorCode.EINVAL; var shadowAddr = FindShadowAddr(current, uaddr); if (shadowAddr == Pointer.Zero) { Arch.Console.WriteLine("FutexShared: Don't know how to deal with shared_wake"); return 0; } var c = new BridgeCompletion(current, new ByteBufferRef()); Arch.IPCStubs.linux_sys_futex_wake(current.Parent.helperPid, current.impl._value.thread._value, op, shadowAddr, bitset); Globals.CompletionQueue.Enqueue(c); current.SaveState(ref regs); current.AsyncReturn = true; return 0; } return 0; }
private static int Wait(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int flags, int val, bool hasTimeout, timespec ts, uint bitset) { int old_val; if (uaddr.Read(current, out old_val) != 0) return -ErrorCode.EFAULT; if (old_val != val) return -ErrorCode.EWOULDBLOCK; //Arch.Console.Write("wait: addr="); //Arch.Console.Write(uaddr.Value.ToUInt32()); //Arch.Console.Write(" thr="); //Arch.Console.Write(current.Tid); //Arch.Console.WriteLine(); TimerQueueNode node; var futex_entry = new FutexCompletionEntry(current, uaddr, bitset); Globals.FutexLists.InsertAtTail(futex_entry); if (hasTimeout) { node = Globals.TimeoutQueue.Enqueue(ts.ToMilliseconds(), current); futex_entry.timeoutNode = node; } Globals.CompletionQueue.Enqueue(futex_entry); current.SaveState(ref regs); current.AsyncReturn = true; return 0; }
public static int Poll(Thread current, ref Arch.ExceptionRegisters regs, UserPtr fds, int nfds, int timeout) { if (nfds < 0) return -ErrorCode.EINVAL; var pollfd_size = pollfd.Size * nfds; var buf = Globals.AllocateAlignedCompletionBuffer(pollfd_size); if (!buf.isValid) return -ErrorCode.ENOMEM; var poll_entry = new PollCompletion(current, fds, nfds, buf); if (fds.Read(current, buf, pollfd_size) != 0) { poll_entry.Dispose(); return -ErrorCode.EFAULT; } Contract.Assert(buf.Length >= pollfd_size); if (!TranslateToLinuxFd(current, poll_entry, buf)) { poll_entry.Dispose(); return -ErrorCode.EBADF; } var ret = Arch.IPCStubs.PollAsync(current.Parent.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), nfds, timeout); if (ret < 0) { poll_entry.Dispose(); return ret; } Globals.CompletionQueue.Enqueue(poll_entry); current.SaveState(ref regs); current.AsyncReturn = true; return 0; }
internal int Write(Thread current, ref Arch.ExceptionRegisters regs, UserPtr userBuf, int len, uint pos, File file) { var buf = Globals.AllocateAlignedCompletionBuffer(len); if (!buf.isValid) return -ErrorCode.ENOMEM; var l = userBuf.Read(current, buf, len); var bytesToBeWritten = len - l; var ret = Write(current, ref regs, ref buf, bytesToBeWritten, pos, file); // Buffer hasn't been taken by write(), free it here if (buf.isValid) Globals.CompletionQueueAllocator.FreePages(new Pointer(buf.Location), buf.Length >> Arch.ArchDefinition.PageShift); return ret; }
public static int Writev(Thread current, ref Arch.ExceptionRegisters regs, int fd, UserPtr iovPtr, int iovcnt) { if (iovcnt < 0) return -ErrorCode.EINVAL; if (iovcnt == 0) return 0; var proc = current.Parent; var file = proc.LookupFile(fd); if (file == null) return -ErrorCode.EBADF; var mode = file.flags & FileFlags.ReadWriteMask; if (mode == FileFlags.ReadOnly) return -ErrorCode.EPERM; var iovec_buf = new byte[IOVector.Size * iovcnt]; if (iovPtr.Read(current, iovec_buf, iovec_buf.Length) != 0) { Arch.Console.WriteLine("Cannot read iovec"); return -ErrorCode.EFAULT; } int totalLength = 0; for (int i = 0; i < iovcnt; ++i) { Contract.Assert((i + 1) * IOVector.Size <= iovec_buf.Length); var iovec = IOVector.Deserialize(iovec_buf, i * IOVector.Size); totalLength += iovec.iov_len; } var buf = Globals.AllocateAlignedCompletionBuffer(totalLength); if (!buf.isValid) return -ErrorCode.ENOMEM; int cursor = 0; for (int i = 0; i < iovcnt; ++i) { Contract.Assert((i + 1) * IOVector.Size <= iovec_buf.Length); var iovec = IOVector.Deserialize(iovec_buf, i * IOVector.Size); var chunk = buf.Slice(cursor, iovec.iov_len); // Post condition of Slice Contract.Assume(chunk.Length >= iovec.iov_len); if (iovec.iov_base.Read(current, chunk, iovec.iov_len) != 0) { Globals.CompletionQueueAllocator.FreePages(new Pointer(buf.Location), buf.Length >> Arch.ArchDefinition.PageShift); return -ErrorCode.EFAULT; } cursor += iovec.iov_len; } int ret = file.Write(current, ref regs, ref buf, totalLength); if (buf.isValid) Globals.CompletionQueueAllocator.FreePages(new Pointer(buf.Location), buf.Length >> Arch.ArchDefinition.PageShift); return ret; }
public static int Writev(Thread current, ref Arch.ExceptionRegisters regs, int fd, UserPtr iovPtr, int iovcnt) { if (iovcnt < 0) { return(-ErrorCode.EINVAL); } if (iovcnt == 0) { return(0); } var proc = current.Parent; var file = proc.LookupFile(fd); if (file == null) { return(-ErrorCode.EBADF); } var mode = file.flags & FileFlags.ReadWriteMask; if (mode == FileFlags.ReadOnly) { return(-ErrorCode.EPERM); } var iovec_buf = new byte[IOVector.Size * iovcnt]; if (iovPtr.Read(current, iovec_buf) != 0) { Arch.Console.WriteLine("Cannot read iovec"); return(-ErrorCode.EFAULT); } int totalLength = 0; for (int i = 0; i < iovcnt; ++i) { Contract.Assert((i + 1) * IOVector.Size <= iovec_buf.Length); var iovec = IOVector.Deserialize(iovec_buf, i * IOVector.Size); totalLength += iovec.iov_len; } var buf = Globals.AllocateAlignedCompletionBuffer(totalLength); if (!buf.isValid) { return(-ErrorCode.ENOMEM); } int cursor = 0; for (int i = 0; i < iovcnt; ++i) { Contract.Assert((i + 1) * IOVector.Size <= iovec_buf.Length); var iovec = IOVector.Deserialize(iovec_buf, i * IOVector.Size); var chunk = buf.Slice(cursor, iovec.iov_len); // Post condition of Slice Contract.Assume(chunk.Length >= iovec.iov_len); if (iovec.iov_base.Read(current, chunk, iovec.iov_len) != 0) { Globals.CompletionQueueAllocator.FreePages(new Pointer(buf.Location), buf.Length >> Arch.ArchDefinition.PageShift); return(-ErrorCode.EFAULT); } cursor += iovec.iov_len; } int ret = file.Write(current, ref regs, ref buf, totalLength); if (buf.isValid) { Globals.CompletionQueueAllocator.FreePages(new Pointer(buf.Location), buf.Length >> Arch.ArchDefinition.PageShift); } return(ret); }
internal static int AshmemIoctl(GenericINode generic_inode, Thread current, uint cmd, UserPtr arg1) { Contract.Requires(Globals.LinuxIPCBuffer.Length >= AshmemINode.ASHMEM_PIN_SIZE); int ret = 0; switch (cmd) { case AshmemINode.ASHMEM_SET_NAME: arg1.ReadString(current, Globals.LinuxIPCBuffer); break; case AshmemINode.ASHMEM_PIN: case AshmemINode.ASHMEM_UNPIN: if (arg1.Read(current, Globals.LinuxIPCBuffer, AshmemINode.ASHMEM_PIN_SIZE) != 0) { ret = -ErrorCode.EFAULT; } break; case AshmemINode.ASHMEM_GET_NAME: case AshmemINode.ASHMEM_SET_SIZE: case AshmemINode.ASHMEM_GET_SIZE: case AshmemINode.ASHMEM_SET_PROT_MASK: case AshmemINode.ASHMEM_GET_PROT_MASK: case AshmemINode.ASHMEM_GET_PIN_STATUS: case AshmemINode.ASHMEM_PURGE_ALL_CACHES: break; default: ret = -ErrorCode.ENOSYS; break; } if (ret < 0) { return(ret); } var linux_fd = generic_inode.LinuxFd; ret = Arch.IPCStubs.linux_sys_vfs_ashmem_ioctl(current.Parent.helperPid, linux_fd, cmd, arg1.Value.ToInt32()); if (ret < 0) { return(ret); } // unmarshal if necessary if (cmd == AshmemINode.ASHMEM_GET_NAME) { var length = Util.Strnlen(Globals.LinuxIPCBuffer, AshmemINode.ASHMEM_NAME_LEN); // include terminator if (length < AshmemINode.ASHMEM_NAME_LEN) { length++; } var buf = Globals.LinuxIPCBuffer.Slice(0, length); if (arg1.Write(current, Globals.LinuxIPCBuffer) != 0) { return(-ErrorCode.EFAULT); } } return(ret); }
private static int Getsockname(Thread current, ref Arch.ExceptionRegisters regs, int sockfd, UserPtr sockaddr, UserPtr p_addrlen) { var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) return -ErrorCode.EBADF; if (file.inode.kind != GenericINode.INodeKind.SocketINodeKind) return -ErrorCode.ENOTSOCK; int addrlen; if (p_addrlen.Read(current, out addrlen) != 0) return -ErrorCode.EFAULT; if (addrlen > Globals.LinuxIPCBuffer.Length) return -ErrorCode.EINVAL; var buf = Globals.AllocateAlignedCompletionBuffer((int)addrlen); if (!buf.isValid) return -ErrorCode.ENOMEM; var completion = new GetSockParamCompletion(current, sockaddr, p_addrlen, buf); Arch.IPCStubs.GetsockNameAsync(proc.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), file.inode.LinuxFd, addrlen); Globals.CompletionQueue.Enqueue(completion); current.SaveState(ref regs); current.AsyncReturn = true; return 0; }
private static int BindOrConnect(int type, Thread current, ref Arch.ExceptionRegisters regs, int sockfd, UserPtr sockaddr, int addrlen) { Contract.Requires(type == SYS_BIND || type == SYS_CONNECT); var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) return -ErrorCode.EBADF; if (file.inode.kind != GenericINode.INodeKind.SocketINodeKind) return -ErrorCode.ENOTSOCK; if (addrlen > Globals.LinuxIPCBuffer.Length) return -ErrorCode.EINVAL; var buf = Globals.AllocateAlignedCompletionBuffer(addrlen); if (!buf.isValid) return -ErrorCode.ENOMEM; var completion = new BridgeCompletion(current, buf); if (sockaddr.Read(current, buf, addrlen) != 0) { completion.Dispose(); return -ErrorCode.EFAULT; } if (type == SYS_BIND) { Arch.IPCStubs.BindAsync(proc.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), file.inode.LinuxFd, addrlen); } else if (type == SYS_CONNECT) { Arch.IPCStubs.ConnectAsync(proc.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), file.inode.LinuxFd, addrlen); } Globals.CompletionQueue.Enqueue(completion); current.SaveState(ref regs); current.AsyncReturn = true; return 0; }
public static int socketcall(Thread current, ref Arch.ExceptionRegisters regs, int call, UserPtr argPtr) { int err = 0; int a0, a1, a2, a3, a4, a5; SyscallProfiler.EnterSocketcall(call); switch (call) { case SYS_SOCKET: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0) { return(-ErrorCode.EFAULT); } err = Socket(current, ref regs, a0, a1, a2); break; case SYS_BIND: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0) { return(-ErrorCode.EFAULT); } err = Bind(current, ref regs, a0, new UserPtr(a1), a2); break; case SYS_CONNECT: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0) { return(-ErrorCode.EFAULT); } err = Connect(current, ref regs, a0, new UserPtr(a1), a2); break; case SYS_GETSOCKNAME: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0) { return(-ErrorCode.EFAULT); } err = Getsockname(current, ref regs, a0, new UserPtr(a1), new UserPtr(a2)); break; case SYS_SENDTO: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0 || (argPtr + sizeof(int) * 3).Read(current, out a3) != 0 || (argPtr + sizeof(int) * 4).Read(current, out a4) != 0 || (argPtr + sizeof(int) * 5).Read(current, out a5) != 0) { return(-ErrorCode.EFAULT); } err = Sendto(current, a0, new UserPtr(a1), a2, a3, new UserPtr(a4), a5); break; case SYS_RECVFROM: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0 || (argPtr + sizeof(int) * 3).Read(current, out a3) != 0 || (argPtr + sizeof(int) * 4).Read(current, out a4) != 0 || (argPtr + sizeof(int) * 5).Read(current, out a5) != 0) { return(-ErrorCode.EFAULT); } err = RecvFrom(current, a0, new UserPtr(a1), a2, a3, new UserPtr(a4), new UserPtr(a5)); break; case SYS_SHUTDOWN: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0) { return(-ErrorCode.EFAULT); } err = Shutdown(current, a0, a1); break; case SYS_SETSOCKOPT: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0 || (argPtr + sizeof(int) * 3).Read(current, out a3) != 0 || (argPtr + sizeof(int) * 4).Read(current, out a4) != 0) { return(-ErrorCode.EFAULT); } err = Setsockopt(current, ref regs, a0, a1, a2, new UserPtr(a3), a4); break; case SYS_GETSOCKOPT: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0 || (argPtr + sizeof(int) * 3).Read(current, out a3) != 0 || (argPtr + sizeof(int) * 4).Read(current, out a4) != 0) { return(-ErrorCode.EFAULT); } err = Getsockopt(current, ref regs, a0, a1, a2, new UserPtr(a3), new UserPtr(a4)); break; default: Arch.Console.Write("Unimplemented socketcall "); Arch.Console.Write(call); Arch.Console.WriteLine(); err = -1; break; } SyscallProfiler.ExitSocketcall(call); return(err); }
private static int RecvFrom(Thread current, int sockfd, UserPtr userBuf, int len, int flags, UserPtr sockaddr, UserPtr p_addrlen) { var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) return -ErrorCode.EBADF; int addrlen; if (p_addrlen.Read(current, out addrlen) != 0) return -ErrorCode.EFAULT; var buf = Globals.LinuxIPCBuffer; if (len + addrlen > buf.Length) { return -ErrorCode.ENOMEM; } var ret = Arch.IPCStubs.Recvfrom(proc.helperPid, file.inode.LinuxFd, len, flags, ref addrlen); if (ret < 0) return ret; var left = userBuf.Write(current, new Pointer(buf.Location), ret); if (sockaddr.Write(current, new Pointer(buf.Location + ret - left), addrlen) != 0) return -ErrorCode.EFAULT; return ret - left; }
public static int Select(Thread current, ref Arch.ExceptionRegisters regs, int maxfds, UserPtr inp, UserPtr outp, UserPtr exp, UserPtr tvp) { var helper = new SelectHelper(); int ret = 0; ret = helper.AddUserFdList(current, inp, maxfds, POLLIN); if (ret < 0) { return(ret); } ret = helper.AddUserFdList(current, outp, maxfds, POLLOUT); if (ret < 0) { return(ret); } ret = helper.AddUserFdList(current, exp, maxfds, POLLERR); if (ret < 0) { return(ret); } int timeout = 0; timeval tv; if (tvp == UserPtr.Zero) { timeout = -1; } else if (tvp.Read(current, out tv) != 0) { return(-ErrorCode.EFAULT); } else { timeout = (int)(tv.tv_sec * 1000 + tv.tv_usec / 1000); } var nfds = helper.TotalFds; var pollfd_size = pollfd.Size * nfds; var buf = Globals.AllocateAlignedCompletionBuffer(pollfd_size); if (!buf.isValid) { return(-ErrorCode.ENOMEM); } helper.WritePollFds(buf); var select_entry = new SelectCompletion(current, maxfds, inp, outp, exp, helper, buf); ret = Arch.IPCStubs.PollAsync(current.Parent.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), nfds, timeout); if (ret < 0) { select_entry.Dispose(); return(ret); } Globals.CompletionQueue.Enqueue(select_entry); current.SaveState(ref regs); current.AsyncReturn = true; return(0); }
private static int Sendto(Thread current, int sockfd, UserPtr userBuf, int len, int flags, UserPtr sockaddr, int addrlen) { var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) return -ErrorCode.EBADF; var buf = Globals.LinuxIPCBuffer; if (len < 0 || addrlen < 0) return -ErrorCode.EINVAL; if (len + addrlen > buf.Length) return -ErrorCode.ENOMEM; if (sockaddr == UserPtr.Zero && addrlen != 0) return -ErrorCode.EINVAL; Contract.Assert(buf.Length >= len + addrlen); if (userBuf.Read(current, buf, len) != 0) return -ErrorCode.EFAULT; var old_buf_len = buf.Length; var sockaddr_buf = buf.Slice(len, buf.Length - len); // Post-condition of ByteBufferRef#ctor and slice Contract.Assume(buf.Length == old_buf_len); Contract.Assume(sockaddr_buf.Length == buf.Length - len); Contract.Assert(buf.Length - len >= addrlen); if (sockaddr != UserPtr.Zero && sockaddr.Read(current, sockaddr_buf, addrlen) != 0) return -ErrorCode.EFAULT; return Arch.IPCStubs.Sendto(proc.helperPid, file.inode.LinuxFd, len, flags, addrlen); }
private static int Setsockopt(Thread current, ref Arch.ExceptionRegisters regs, int sockfd, int level, int optname, UserPtr optval, int optlen) { var proc = current.Parent; var file = proc.LookupFile(sockfd); if (file == null) return -ErrorCode.EBADF; if (file.inode.kind != GenericINode.INodeKind.SocketINodeKind) return -ErrorCode.ENOTSOCK; if (optlen > Globals.LinuxIPCBuffer.Length) return -ErrorCode.EINVAL; var buf = Globals.AllocateAlignedCompletionBuffer(optlen); if (!buf.isValid) return -ErrorCode.ENOMEM; var completion = new BridgeCompletion(current, buf); if (optval.Read(current, buf, optlen) != 0) { completion.Dispose(); return -ErrorCode.EFAULT; } Arch.IPCStubs.SetSockoptAsync(proc.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), file.inode.LinuxFd, level, optname, optlen); Globals.CompletionQueue.Enqueue(completion); current.SaveState(ref regs); current.AsyncReturn = true; return 0; }
private int MarshalDataSegments(int size, ref UserPtr data, int offset) { Contract.Requires(size >= 0); Contract.Ensures(ReadCursor == Contract.OldValue(ReadCursor)); if (size == 0) return 0; if (size > buf.Length - WriteCursor) return -ErrorCode.ENOMEM; var b = buf.Slice(WriteCursor, size); // Post condition for ByteBufferRef Contract.Assume(b.Length == size); var r = data.Read(current, b, size); if (r != 0) return -ErrorCode.EFAULT; data = new UserPtr((uint)WriteCursor); WriteCursor += size; // Add patch entry if (CurrentPatchEntry >= kPatchTableSize) return -ErrorCode.ENOMEM; patchTable[CurrentPatchEntry++] = ReadCursor + offset; return 0; }
public static int socketcall(Thread current, ref Arch.ExceptionRegisters regs, int call, UserPtr argPtr) { int err = 0; int a0, a1, a2, a3, a4, a5; SyscallProfiler.EnterSocketcall(call); switch (call) { case SYS_SOCKET: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0) return -ErrorCode.EFAULT; err = Socket(current, ref regs, a0, a1, a2); break; case SYS_BIND: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0) return -ErrorCode.EFAULT; err = Bind(current, ref regs, a0, new UserPtr(a1), a2); break; case SYS_CONNECT: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0) return -ErrorCode.EFAULT; err = Connect(current, ref regs, a0, new UserPtr(a1), a2); break; case SYS_GETSOCKNAME: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0) return -ErrorCode.EFAULT; err = Getsockname(current, ref regs, a0, new UserPtr(a1), new UserPtr(a2)); break; case SYS_SENDTO: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0 || (argPtr + sizeof(int) * 3).Read(current, out a3) != 0 || (argPtr + sizeof(int) * 4).Read(current, out a4) != 0 || (argPtr + sizeof(int) * 5).Read(current, out a5) != 0) return -ErrorCode.EFAULT; err = Sendto(current, a0, new UserPtr(a1), a2, a3, new UserPtr(a4), a5); break; case SYS_RECVFROM: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0 || (argPtr + sizeof(int) * 3).Read(current, out a3) != 0 || (argPtr + sizeof(int) * 4).Read(current, out a4) != 0 || (argPtr + sizeof(int) * 5).Read(current, out a5) != 0) return -ErrorCode.EFAULT; err = RecvFrom(current, a0, new UserPtr(a1), a2, a3, new UserPtr(a4), new UserPtr(a5)); break; case SYS_SHUTDOWN: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0) return -ErrorCode.EFAULT; err = Shutdown(current, a0, a1); break; case SYS_SETSOCKOPT: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0 || (argPtr + sizeof(int) * 3).Read(current, out a3) != 0 || (argPtr + sizeof(int) * 4).Read(current, out a4) != 0) return -ErrorCode.EFAULT; err = Setsockopt(current, ref regs, a0, a1, a2, new UserPtr(a3), a4); break; case SYS_GETSOCKOPT: if (argPtr.Read(current, out a0) != 0 || (argPtr + sizeof(int)).Read(current, out a1) != 0 || (argPtr + sizeof(int) * 2).Read(current, out a2) != 0 || (argPtr + sizeof(int) * 3).Read(current, out a3) != 0 || (argPtr + sizeof(int) * 4).Read(current, out a4) != 0) return -ErrorCode.EFAULT; err = Getsockopt(current, ref regs, a0, a1, a2, new UserPtr(a3), new UserPtr(a4)); break; default: Arch.Console.Write("Unimplemented socketcall "); Arch.Console.Write(call); Arch.Console.WriteLine(); err = -1; break; } SyscallProfiler.ExitSocketcall(call); return err; }
internal int Marshal(UserPtr writeBuf, int size) { if (size < 0 || size > buf.Length) return -ErrorCode.EINVAL; ReadCursor = 0; // Copy the full data into the buffer, but don't increment the read pointer yet. var r = writeBuf.Read(current, buf, size); if (r != 0) return -1; // Advance the cursor WriteCursor = size; // parse the command while (ReadCursor < size) { if (ReadCursor + sizeof(uint) > buf.Length) return -ErrorCode.ENOMEM; var cmd = Deserializer.ReadUInt(buf, ReadCursor); ReadCursor += sizeof(uint); switch (cmd) { case BinderINode.BC_INCREFS: case BinderINode.BC_ACQUIRE: case BinderINode.BC_RELEASE: case BinderINode.BC_DECREFS: ReadCursor += sizeof(int); break; case BinderINode.BC_INCREFS_DONE: case BinderINode.BC_ACQUIRE_DONE: case BinderINode.BC_REQUEST_DEATH_NOTIFICATION: case BinderINode.BC_CLEAR_DEATH_NOTIFICATION: ReadCursor += Pointer.Size * 2; break; case BinderINode.BC_ATTEMPT_ACQUIRE: case BinderINode.BC_ACQUIRE_RESULT: // Unimplemented in Android IPC return -ErrorCode.EINVAL; case BinderINode.BC_FREE_BUFFER: { if (ReadCursor + sizeof(uint) > buf.Length) return -ErrorCode.ENOMEM; var addr = Deserializer.ReadUInt(buf, ReadCursor); var new_val = addr - current.Parent.binderVMStart.Value.ToUInt32() + current.Parent.ShadowBinderVMStart; Deserializer.WriteUInt(new_val, buf, ReadCursor); ReadCursor += Pointer.Size; break; } case BinderINode.BC_TRANSACTION: case BinderINode.BC_REPLY: { var ret = MarshalTransaction(); if (ret < 0) return ret; break; } case BinderINode.BC_REGISTER_LOOPER: case BinderINode.BC_ENTER_LOOPER: case BinderINode.BC_EXIT_LOOPER: break; default: Arch.Console.Write("binder: unsupported IPC primitive "); Arch.Console.Write(cmd); Arch.Console.WriteLine(); return -1; } } r = AppendPatchTable(); if (r != 0) return -1; //Arch.Console.Write("Dump write buffer "); //Arch.Console.Write(current.Tid); //Arch.Console.WriteLine(); //DumpBuf(new Pointer(buf.Location), size); return 0; }
public static int Select(Thread current, ref Arch.ExceptionRegisters regs, int maxfds, UserPtr inp, UserPtr outp, UserPtr exp, UserPtr tvp) { var helper = new SelectHelper(); int ret = 0; ret = helper.AddUserFdList(current, inp, maxfds, POLLIN); if (ret < 0) return ret; ret = helper.AddUserFdList(current, outp, maxfds, POLLOUT); if (ret < 0) return ret; ret = helper.AddUserFdList(current, exp, maxfds, POLLERR); if (ret < 0) return ret; int timeout = 0; timeval tv; if (tvp == UserPtr.Zero) { timeout = -1; } else if (tvp.Read(current, out tv) != 0) { return -ErrorCode.EFAULT; } else { timeout = (int)(tv.tv_sec * 1000 + tv.tv_usec / 1000); } var nfds = helper.TotalFds; var pollfd_size = pollfd.Size * nfds; var buf = Globals.AllocateAlignedCompletionBuffer(pollfd_size); if (!buf.isValid) return -ErrorCode.ENOMEM; helper.WritePollFds(buf); var select_entry = new SelectCompletion(current, maxfds, inp, outp, exp, helper, buf); ret = Arch.IPCStubs.PollAsync(current.Parent.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), nfds, timeout); if (ret < 0) { select_entry.Dispose(); return ret; } Globals.CompletionQueue.Enqueue(select_entry); current.SaveState(ref regs); current.AsyncReturn = true; return 0; }
private static int Send(Thread current, int cap_idx, UserPtr userBuf, uint size) { if (!current.Parent.Space.VerifyRead(userBuf, size)) return -ErrorCode.EFAULT; var cap_ref = current.VBinderState.Find(current, cap_idx); if (cap_ref == null) return -ErrorCode.EINVAL; var blob = Globals.AllocateAlignedCompletionBuffer((int)size); if (!blob.isValid) return -ErrorCode.ENOMEM; if (userBuf.Read(current, blob, (int)size) != 0) return -ErrorCode.EFAULT; var targetThread = cap_ref.def.parent; // Object invariant of thread Contract.Assume(targetThread.VBinderState.Owner == targetThread); var msg = new VBinderMessage(current, targetThread, cap_ref.def.label, blob, (int)size); if (targetThread.VBinderState.Completion != null) { HandleAsyncCall(targetThread, msg); } else { Contract.Assert(msg.GhostTarget == targetThread); targetThread.VBinderState.Enqueue(msg); } return (int)size; }
internal int Marshal(UserPtr writeBuf, int size) { if (size < 0 || size > buf.Length) { return(-ErrorCode.EINVAL); } ReadCursor = 0; // Copy the full data into the buffer, but don't increment the read pointer yet. var r = writeBuf.Read(current, buf, size); if (r != 0) { return(-1); } // Advance the cursor WriteCursor = size; // parse the command while (ReadCursor < size) { if (ReadCursor + sizeof(uint) > buf.Length) { return(-ErrorCode.ENOMEM); } var cmd = Deserializer.ReadUInt(buf, ReadCursor); ReadCursor += sizeof(uint); switch (cmd) { case BinderINode.BC_INCREFS: case BinderINode.BC_ACQUIRE: case BinderINode.BC_RELEASE: case BinderINode.BC_DECREFS: ReadCursor += sizeof(int); break; case BinderINode.BC_INCREFS_DONE: case BinderINode.BC_ACQUIRE_DONE: case BinderINode.BC_REQUEST_DEATH_NOTIFICATION: case BinderINode.BC_CLEAR_DEATH_NOTIFICATION: ReadCursor += Pointer.Size * 2; break; case BinderINode.BC_ATTEMPT_ACQUIRE: case BinderINode.BC_ACQUIRE_RESULT: // Unimplemented in Android IPC return(-ErrorCode.EINVAL); case BinderINode.BC_FREE_BUFFER: { if (ReadCursor + sizeof(uint) > buf.Length) { return(-ErrorCode.ENOMEM); } var addr = Deserializer.ReadUInt(buf, ReadCursor); var new_val = addr - current.Parent.binderVMStart.Value.ToUInt32() + current.Parent.ShadowBinderVMStart; Deserializer.WriteUInt(new_val, buf, ReadCursor); ReadCursor += Pointer.Size; break; } case BinderINode.BC_TRANSACTION: case BinderINode.BC_REPLY: { var ret = MarshalTransaction(); if (ret < 0) { return(ret); } break; } case BinderINode.BC_REGISTER_LOOPER: case BinderINode.BC_ENTER_LOOPER: case BinderINode.BC_EXIT_LOOPER: break; default: Arch.Console.Write("binder: unsupported IPC primitive "); Arch.Console.Write(cmd); Arch.Console.WriteLine(); return(-1); } } r = AppendPatchTable(); if (r != 0) { return(-1); } //Arch.Console.Write("Dump write buffer "); //Arch.Console.Write(current.Tid); //Arch.Console.WriteLine(); //DumpBuf(new Pointer(buf.Location), size); return(0); }
// Forward the futex request to Linux helper private static int DoFutexShared(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int op, int val, UserPtr timeoutPtr, UserPtr uaddr2, uint val3) { // Some local test var cmd = op & FUTEX_CMD_MASK; timespec ts = new timespec(); bool hasTimeout = timeoutPtr != UserPtr.Zero; if (hasTimeout && timeoutPtr.Read(current, out ts) != 0) { return(-ErrorCode.EFAULT); } if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_BITSET) { int old_val; if (uaddr.Read(current, out old_val) != 0) { return(-ErrorCode.EFAULT); } if (old_val != val) { return(-ErrorCode.EWOULDBLOCK); } var bitset = cmd == FUTEX_WAIT ? FUTEX_BITSET_MATCH_ANY : val3; var shadowAddr = FindShadowAddr(current, uaddr); if (shadowAddr == Pointer.Zero) { Arch.Console.WriteLine("FutexShared: Don't know how to deal with shared_wait"); return(0); } var futex_entry = new FutexCompletionEntry(current, uaddr, bitset); Arch.IPCStubs.linux_sys_futex_wait(current.Parent.helperPid, current.impl._value.thread._value, op, shadowAddr, val, ts, bitset); Globals.CompletionQueue.Enqueue(futex_entry); current.SaveState(ref regs); current.AsyncReturn = true; return(0); } else if (cmd == FUTEX_WAKE || cmd == FUTEX_WAKE_BITSET) { var bitset = cmd == FUTEX_WAKE ? FUTEX_BITSET_MATCH_ANY : val3; if (bitset == 0) { return(-ErrorCode.EINVAL); } var shadowAddr = FindShadowAddr(current, uaddr); if (shadowAddr == Pointer.Zero) { Arch.Console.WriteLine("FutexShared: Don't know how to deal with shared_wake"); return(0); } var c = new BridgeCompletion(current, new ByteBufferRef()); Arch.IPCStubs.linux_sys_futex_wake(current.Parent.helperPid, current.impl._value.thread._value, op, shadowAddr, bitset); Globals.CompletionQueue.Enqueue(c); current.SaveState(ref regs); current.AsyncReturn = true; return(0); } return(0); }
public static int Nanosleep(Thread current, ref Arch.ExceptionRegisters regs, UserPtr rqtp, UserPtr rmtp) { timespec ts; timespec trem; trem.tv_sec = 0; trem.tv_nsec = 0; if (rqtp.Read(current, out ts) != 0 || rmtp.Write(current, ref trem) != 0) return -ErrorCode.EFAULT; Globals.TimeoutQueue.Enqueue(ts.ToMilliseconds(), current); var c = new SleepCompletion(current); Globals.CompletionQueue.Enqueue(c); current.SaveState(ref regs); current.AsyncReturn = true; return 0; }