public int Read(Thread current, ref Arch.ExceptionRegisters regs, UserPtr userBuf, int len, uint pos) { Contract.Requires(GhostOwner == current.Parent); var ret = inode.Read(current, ref regs, userBuf, len, pos, null); return(ret); }
private int Ioctl(Thread current, uint cmd, UserPtr arg1) { //Arch.Console.Write("ioctl:, cmd="); //Arch.Console.Write(cmd); //Arch.Console.WriteLine(); // marshal arguments switch (cmd) { case AshmemINode.ASHMEM_SET_NAME: case AshmemINode.ASHMEM_PIN: case AshmemINode.ASHMEM_UNPIN: 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: return(AshmemINode.AshmemIoctl(this, current, cmd, arg1)); case FileSystem.FIONREAD: return(LinuxIoctl(current, cmd, arg1)); default: return(-1); } }
private static int Recv(Thread current, ref Arch.ExceptionRegisters regs, UserPtr ptr_label, UserPtr userBuf, uint size) { Contract.Requires(current.VBinderState.Owner == current); if (!current.Parent.Space.VerifyWrite(userBuf, size) || !current.Parent.Space.VerifyWrite(ptr_label, sizeof(int))) { return(-ErrorCode.EFAULT); } var b = current.VBinderState.NoPendingMessages(); if (b) { var entry = new VBinderCompletion(current, ptr_label, userBuf, size); current.VBinderState.Completion = entry; current.SaveState(ref regs); current.AsyncReturn = true; return(0); } else { var msg = current.VBinderState.TakeMessage(); Contract.Assert(msg.GhostTarget == current); var length = msg.Length; ptr_label.Write(current.Parent, msg.label); userBuf.Write(current, new Pointer(msg.payload.Location), length); msg.Recycle(); return(length); } }
private int LinuxIoctl(Thread current, uint cmd, UserPtr arg1) { var msg_buf = Globals.LinuxIPCBuffer; int ret = 0; // marshal arguments switch (cmd) { case FileSystem.FIONREAD: break; default: return(-ErrorCode.ENOTTY); } ret = Arch.IPCStubs.linux_sys_vfs_linux_ioctl(current.Parent.helperPid, LinuxFd, cmd, arg1.Value.ToInt32()); if (ret < 0) { return(ret); } // unmarshal if necessary if (cmd == FileSystem.FIONREAD) { if (arg1.Write(current, new Pointer(msg_buf.Location), sizeof(int)) != 0) { return(-ErrorCode.EFAULT); } } return(ret); }
internal int Write(Thread current, ref Arch.ExceptionRegisters regs, UserPtr userBuf, int len) { Contract.Requires(GhostOwner == current.Parent); var ret = inode.Write(current, ref regs, userBuf, len, position, this); return(ret); }
private static int StatAt64(Thread current, UserPtr filenamePtr, UserPtr buf, bool followSymlink) { var proc = current.Parent; int err; filenamePtr.ReadString(current, Globals.LinuxIPCBuffer); if (followSymlink) { err = Arch.IPCStubs.linux_sys_stat64(proc.helperPid); } else { err = Arch.IPCStubs.linux_sys_lstat64(proc.helperPid); } if (err != 0) { return(err); } if (buf.Write(current, new Pointer(Globals.LinuxIPCBuffer.Location), SIZE_OF_STAT64) != 0) { return(-ErrorCode.EFAULT); } return(0); }
public static int ClockGetTime(Thread current, int clock_id, UserPtr tp) { timespec res; res.tv_nsec = res.tv_sec = 0; switch (clock_id) { case CLOCK_REALTIME: case CLOCK_PROCESS_CPUTIME_ID: case CLOCK_THREAD_CPUTIME_ID: res = GetTime(UptimeTimeSpec); break; case CLOCK_MONOTONIC: res = GetTime(MonotonicTimeSpec); break; default: Arch.Console.Write("Unimplemented ClockGetTime:"); Arch.Console.Write(clock_id); Arch.Console.WriteLine(); return(-ErrorCode.ENOSYS); } if (tp.Write(current, ref res) != 0) { return(-ErrorCode.EFAULT); } return(0); }
public static int Access(Thread current, ref Arch.ExceptionRegisters regs, UserPtr filenamePtr, int mode) { // XXX: This is vfs related, now let's assume that we're dealing with pass through fs. var buf = Globals.AllocateAlignedCompletionBuffer(PATH_MAX); if (!buf.isValid) return -ErrorCode.ENOMEM; var ret = filenamePtr.ReadString(current, buf); var accessCompletion = new BridgeCompletion(current, buf); ret = Arch.IPCStubs.AccessAsync(current.Parent.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), mode); if (ret < 0) { accessCompletion.Dispose(); return ret; } Globals.CompletionQueue.Enqueue(accessCompletion); current.SaveState(ref regs); current.AsyncReturn = true; return 0; }
internal int TranslateToUserFdlist(Thread current, ByteBufferRef buf, int poll_ret, int maxfds, UserPtr userPtr, short event_type) { Contract.Requires(poll_ret * pollfd.Size < buf.Length); if (userPtr == UserPtr.Zero) return 0; var res = 0; var len = (maxfds + 7) / 8; var vec = new FixedSizeBitVector(maxfds); for (int i = 0; i < poll_ret; i++) { var poll_struct = pollfd.Deserialize(buf, i * pollfd.Size); var linux_fd = poll_struct.fd; var node = Lookup(linux_fd); if (node == null) return -ErrorCode.EBADF; if ((poll_struct.revents & event_type & node.event_type) != 0) { vec.Set(node.expressos_fd); ++res; } } if (userPtr.Write(current, vec.Buffer) != 0) return -ErrorCode.EFAULT; return res; }
public static int ClockGetTime(Thread current, int clock_id, UserPtr tp) { timespec res; res.tv_nsec = res.tv_sec = 0; switch (clock_id) { case CLOCK_REALTIME: case CLOCK_PROCESS_CPUTIME_ID: case CLOCK_THREAD_CPUTIME_ID: res = GetTime(UptimeTimeSpec); break; case CLOCK_MONOTONIC: res = GetTime(MonotonicTimeSpec); break; default: Arch.Console.Write("Unimplemented ClockGetTime:"); Arch.Console.Write(clock_id); Arch.Console.WriteLine(); return -ErrorCode.ENOSYS; } if (tp.Write(current, ref res) != 0) return -ErrorCode.EFAULT; return 0; }
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); }
private static int Recv(Thread current, ref Arch.ExceptionRegisters regs, UserPtr ptr_label, UserPtr userBuf, uint size) { Contract.Requires(current.VBinderState.Owner == current); if (!current.Parent.Space.VerifyWrite(userBuf, size) || !current.Parent.Space.VerifyWrite(ptr_label, sizeof(int))) return -ErrorCode.EFAULT; var b = current.VBinderState.NoPendingMessages(); if (b) { var entry = new VBinderCompletion(current, ptr_label, userBuf, size); current.VBinderState.Completion = entry; current.SaveState(ref regs); current.AsyncReturn = true; return 0; } else { var msg = current.VBinderState.TakeMessage(); Contract.Assert(msg.GhostTarget == current); var length = msg.Length; ptr_label.Write(current.Parent, msg.label); userBuf.Write(current, new Pointer(msg.payload.Location), length); msg.Recycle(); return length; } }
public static int Clone(Thread current, uint flags, UserPtr newsp, UserPtr parent_tidptr, UserPtr child_tidptr, ref Arch.ExceptionRegisters pt_regs) { // Only support pthread_create right now if (flags != (CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_DETACHED)) { return(-ErrorCode.EINVAL); } var proc = current.Parent; var thr = Thread.Create(proc); if (thr == null) { Arch.Console.WriteLine("Failed to create thread"); return(-ErrorCode.EINVAL); } // Start the main thread // Skipping the int $0x80 thr.Start(new Pointer(pt_regs.ip + 2), newsp.Value); // There's no need to set eax for thr as they are zero by default.. return(thr.Tid); }
public static int Access(Thread current, ref Arch.ExceptionRegisters regs, UserPtr filenamePtr, int mode) { // XXX: This is vfs related, now let's assume that we're dealing with pass through fs. var buf = Globals.AllocateAlignedCompletionBuffer(PATH_MAX); if (!buf.isValid) { return(-ErrorCode.ENOMEM); } var ret = filenamePtr.ReadString(current, buf); var accessCompletion = new BridgeCompletion(current, buf); ret = Arch.IPCStubs.AccessAsync(current.Parent.helperPid, current.impl._value.thread._value, new Pointer(buf.Location), mode); if (ret < 0) { accessCompletion.Dispose(); return(ret); } Globals.CompletionQueue.Enqueue(accessCompletion); 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; } }
public SelectCompletion(Thread current, int maxfds, UserPtr inp, UserPtr outp, UserPtr exp, SelectHelper helper, ByteBufferRef buf) : base(current, Kind.SelectCompletionKind, buf) { this.fds = maxfds; this.inp = inp; this.outp = outp; this.exp = exp; this.helper = helper; }
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 PushInt(Process proc, int v, ref UserPtr stack_top) { stack_top -= sizeof(int); if (stack_top.Write(proc, v) != 0) { return(-1); } return(0); }
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); }
public PollCompletion(Thread current, UserPtr fds, int nfds, ByteBufferRef buf) : base(current, Kind.PollCompletionKind, buf) { Contract.Requires(nfds >= 0); Contract.Requires(buf.Length >= nfds * pollfd.Size); Contract.Ensures(fdMaps.Length == nfds); Contract.Ensures(this.buf.Length >= fdMaps.Length * pollfd.Size); this.userFdBuf = fds; this.fdMaps = new int[nfds]; }
internal int FStat64(Thread current, UserPtr buf) { switch (kind) { case INodeKind.ArchINodeKind: return(ArchINode.ArchFStat64(current, buf)); case INodeKind.SecureFSINodeKind: return(SFSINode.SFSFStat64(current, buf)); } return(-ErrorCode.EINVAL); }
public static int Parse(int helperPid, File file, Process proc, ref UserPtr stackTop) { Contract.Requires(file.GhostOwner == proc); Contract.Requires(proc.Space.GhostOwner == proc); var buf = new byte[Size]; uint pos = 0; if (file.Read(buf, ref pos) != buf.Length) return -ErrorCode.EINVAL; var eh = Read(buf); if (eh.type != ELF32Header.ELF_TYPE_EXECUTABLE || eh.ProgramHeaderOffest == 0) return -ErrorCode.ENOEXEC; proc.EntryPoint = eh.EntryPoint; ELF32ProgramHeader ph = new ELF32ProgramHeader(); var ret = FindInterpreter(file, eh, ref ph); if (ret == -ErrorCode.EINVAL) { Arch.Console.WriteLine("Malformed ELF file"); return ret; } else if (ret == 0) { var interpreterBuf = new byte[ph.FileSize]; pos = ph.offset; if (file.Read(interpreterBuf, ref pos) != interpreterBuf.Length) return -ErrorCode.EINVAL; var interpreterName = new ASCIIString(interpreterBuf); ErrorCode ec; var interpreter_inode = Arch.ArchFS.Open(helperPid, interpreterName, 0, 0, out ec); if (interpreter_inode == null) return -ErrorCode.ENOENT; var interpreter = new File(proc, interpreter_inode, FileFlags.ReadOnly, 0); /* * Parse the information of linker. * * This function will also override the entry point. */ if (Parse(helperPid, interpreter, proc, ref stackTop) != 0) return -ErrorCode.EINVAL; // So now let's copy the program header to the top of the stack, and push auxlirary vectors PushProgramHeaderAndAuxliraryVectors(proc, file, eh, ref stackTop); } return MapInSegments(file, proc, eh); }
internal int Read(Thread current, ref Arch.ExceptionRegisters regs, UserPtr userBuf, int len, uint pos, File file) { switch (kind) { case INodeKind.ArchINodeKind: case INodeKind.SocketINodeKind: return(ArchINode.ArchRead(current, ref regs, userBuf, len, pos, file)); case INodeKind.SecureFSINodeKind: return(SFSINode.SFSRead(current, ref regs, userBuf, len, pos, file)); } return(-ErrorCode.EINVAL); }
//* return values: //* zero - success //* -EINVAL - start + len < 0, start is not page-aligned, //* "behavior" is not a valid value, or application //* is attempting to release locked or shared pages. //* -ENOMEM - addresses in the specified range are not currently //* mapped, or are outside the AS of the process. //* -EIO - an I/O error occurred while paging in data. //* -EBADF - map exists, but area maps something that isn't a file. //* -EAGAIN - a kernel resource was temporarily unavailable. private static int madviseDontNeed(Thread current, uint start, int len) { if (Arch.ArchDefinition.PageOffset(start) != 0 || len < 0) { return(-ErrorCode.EINVAL); } var alignedLength = Arch.ArchDefinition.PageAlign((uint)len); var endPage = new UserPtr(start + alignedLength); current.Parent.Space.workingSet.Remove(current.Parent.Space, new UserPtr(start), endPage); return(0); }
public static int Pipe(Thread current, UserPtr pipeFd) { var proc = current.Parent; var helperPid = proc.helperPid; int fd0, fd1; var ret = Arch.IPCStubs.Pipe(helperPid, out fd0, out fd1); if (ret < 0) { return(ret); } var inode1 = new Arch.ArchINode(fd0, 0, helperPid); var inode2 = new Arch.ArchINode(fd1, 0, helperPid); // XXX: are the permission settings correct? var file1 = new File(proc, inode1, FileFlags.ReadWrite, 0); var rfd0 = proc.GetUnusedFd(); proc.InstallFd(rfd0, file1); var file2 = new File(proc, inode2, FileFlags.ReadWrite, 0); var rfd1 = proc.GetUnusedFd(); proc.InstallFd(rfd1, file2); //Arch.Console.Write("pipe: linux_fd ["); //Arch.Console.Write(fd0); //Arch.Console.Write(","); //Arch.Console.Write(fd1); //Arch.Console.Write("] => ["); //Arch.Console.Write(rfd0); //Arch.Console.Write(","); //Arch.Console.Write(rfd1); //Arch.Console.Write("], ret="); //Arch.Console.Write(ret); //Arch.Console.WriteLine(); if (pipeFd.Write(current, rfd0) != 0 || (pipeFd + sizeof(int)).Write(current, rfd1) != 0) { Arch.IPCStubs.Close(helperPid, fd0); Arch.IPCStubs.Close(helperPid, fd1); return(-ErrorCode.EFAULT); } return(ret); }
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; }
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)); }
public static int Gettimeofday(Thread current, UserPtr timeval) { timespec res = GetTime(UptimeTimeSpec); timeval r; r.tv_sec = res.tv_sec; r.tv_usec = res.tv_nsec / 1000; if (timeval.Write(current, ref r) != 0) { return(-ErrorCode.EFAULT); } 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 UserPtr[] PushCharArray(Process proc, ASCIIString[] arr, ref UserPtr stack_top) { var res = new UserPtr[arr.Length]; for (int i = 0; i < arr.Length; ++i) { // Include the terminator stack_top -= arr[i].Length + 1; res[i] = stack_top; if (stack_top.Write(proc, arr[i].GetByteString()) != 0) { return(null); } } return(res); }
internal int SFSRead(Thread current, ref Arch.ExceptionRegisters regs, UserPtr userBuf, int len, uint pos, File file) { var readBytes = Read(current, userBuf, len, pos); if (readBytes <= 0) { return(readBytes); } if (file != null) { file.position = (uint)(pos + readBytes); } return(readBytes); }
private static int PushArgumentPointers(Process proc, UserPtr[] arr, ref UserPtr stack_top) { if (PushInt(proc, 0, ref stack_top) != 0) { return(-1); } for (int i = arr.Length - 1; i >= 0; --i) { var p = arr[i]; if (PushInt(proc, p.Value.ToInt32(), ref stack_top) != 0) { return(-1); } } return(0); }
internal int SFSFStat64(Thread current, UserPtr buf) { var ret = Arch.IPCStubs.linux_sys_fstat64(helperPid, Fd); if (ret < 0) { return(ret); } FileSystem.SetSizeFromStat64(Globals.LinuxIPCBuffer, FileSize); if (buf.Write(current, new Pointer(Globals.LinuxIPCBuffer.Location), GenericINode.SIZE_OF_STAT64) != 0) { return(-ErrorCode.EFAULT); } return(0); }
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 PushProgramHeaderAndAuxliraryVectors(Process proc, File file, ELF32Header eh, ref UserPtr stackTop) { var programHeaderLength = eh.NumOfProgramHeader * eh.ProgramHeaderSize; var buf = new byte[programHeaderLength]; uint pos = eh.ProgramHeaderOffest; if (file.Read(buf, ref pos) != programHeaderLength) { return(-ErrorCode.ENOMEM); } stackTop -= programHeaderLength; UserPtr ph_ptr = stackTop; if (ph_ptr.Write(proc, buf) != 0) { return(-ErrorCode.ENOMEM); } // align stackTop = UserPtr.RoundDown(stackTop); var aux_vector = new uint[LengthOfAuxVector]; aux_vector[0] = AT_PHDR; aux_vector[1] = ph_ptr.Value.ToUInt32(); aux_vector[2] = AT_ENTRY; aux_vector[3] = eh.EntryPoint; aux_vector[4] = AT_PHNUM; aux_vector[5] = eh.NumOfProgramHeader; aux_vector[6] = 0; aux_vector[7] = 0; var auxVectorSize = sizeof(uint) * LengthOfAuxVector; stackTop -= auxVectorSize; if (stackTop.Write(proc, aux_vector) != 0) { return(-ErrorCode.ENOMEM); } 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); }
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); }
public static int FStat64(Thread current, int fd, UserPtr buf) { var proc = current.Parent; var file = proc.LookupFile(fd); if (file == null) { return(-ErrorCode.EINVAL); } int ret = file.FStat64(current, buf); if (ret < 0) { return(ret); } return(0); }
private int Read(Thread current, UserPtr userBuf, int len, uint pos) { int readBytes = 0; int remainedBytes = len; if (FileSize - pos < remainedBytes) { remainedBytes = (int)(FileSize - pos); } int currentPageIndex = (int)Arch.ArchDefinition.PageIndex(pos); var page = Pages.Lookup(currentPageIndex / Arch.ArchDefinition.PageSize); while (remainedBytes > 0) { if (page == null) { page = CachePage.Allocate(current.Parent, currentPageIndex / Arch.ArchDefinition.PageSize); var succeed = page.Load(this); if (!succeed) { return(-ErrorCode.EIO); } Contract.Assert(page != null && (page.CurrentState == CachePage.State.Empty || page.CurrentState == CachePage.State.Decrypted)); Pages.Add(page); } var pageCursor = (int)((pos + readBytes) % Arch.ArchDefinition.PageSize); var chunkLen = Arch.ArchDefinition.PageSize - pageCursor < remainedBytes ? Arch.ArchDefinition.PageSize - pageCursor : remainedBytes; var left = WriteUserBuffer(current, userBuf, readBytes, page, pageCursor, chunkLen); readBytes += chunkLen - left; if (left != 0) { return(-ErrorCode.EFAULT); } remainedBytes = remainedBytes - chunkLen; currentPageIndex = currentPageIndex + Arch.ArchDefinition.PageSize; page = Pages.Lookup(currentPageIndex / Arch.ArchDefinition.PageSize); } return(readBytes); }
public static int UnmarshalReadBuffer(Thread thr, ByteBufferRef completionBuf, ref sys_binder_write_desc desc, UserPtr readBuffer, int readBufferSize) { var proc = thr.Parent; var marshaledPtr = new Pointer(completionBuf.Location); //Arch.Console.Write("read_consumed:"); //Arch.Console.Write(desc.read_consumed); //BinderIPCMarshaler.DumpBuf(new Pointer(completionBuf.Location), (int)desc.read_consumed); if (proc.binderVMStart == UserPtr.Zero) { Arch.Console.WriteLine("proc.binderVMStart == UserPtr.Zero"); return -ErrorCode.EFAULT; } if (UnmarshalDataEntries(thr, completionBuf, ref desc) != 0) { Arch.Console.WriteLine("UnmarshalDataEntries failed"); return -ErrorCode.ENOMEM; } if (desc.read_consumed > completionBuf.Length) { Arch.Console.WriteLine("UnmarshalReadBuffer: bad input"); return -ErrorCode.ENOMEM; } // Patch pointers and convert file descriptors var b = completionBuf.Slice(0, desc.read_consumed); if (PatchReadBuffer(thr, b) != 0) { Arch.Console.WriteLine("Failed to patch read buffer"); return -ErrorCode.EINVAL; } if (readBuffer.Write(thr, marshaledPtr, desc.read_consumed) != 0) { Arch.Console.WriteLine("readBuffer.Write failed"); return -ErrorCode.ENOMEM; } return 0; }
private static int Wake(Thread current, UserPtr uaddr, int flags, int nr_wake, uint bitset) { if (bitset == 0) { return(-ErrorCode.EINVAL); } var space = current.Parent.Space; int ret = 0; //Arch.Console.Write("Futex_wake: thr="); //Arch.Console.Write(current.Tid); //Arch.Console.Write(" uaddr="); //Arch.Console.Write(uaddr.Value.ToUInt32()); //Arch.Console.Write(" nr_wake="); //Arch.Console.Write(nr_wake); //Arch.Console.WriteLine(); FutexCompletionEntry q; // XXX: For simplicity (right now), we scan through the whole completion queue for (var p = Globals.FutexLists.nextFutex; p != Globals.FutexLists && ret < nr_wake; p = q) { q = p.nextFutex; //Arch.Console.Write("wake_loop: uaddr="); //Arch.Console.Write(p.uaddr.Value.ToUInt32()); //Arch.Console.Write(" tid="); //Arch.Console.Write(p.thr.Tid); //Arch.Console.WriteLine(); if (!(p.Space == space && p.uaddr == uaddr && (p.bitset & bitset) != 0)) { continue; } ++ret; WakeUp(p, true, 0); } return(ret); }
public static int Clone(Thread current, uint flags, UserPtr newsp, UserPtr parent_tidptr, UserPtr child_tidptr, ref Arch.ExceptionRegisters pt_regs) { // Only support pthread_create right now if (flags != (CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_DETACHED)) return -ErrorCode.EINVAL; var proc = current.Parent; var thr = Thread.Create(proc); if (thr == null) { Arch.Console.WriteLine("Failed to create thread"); return -ErrorCode.EINVAL; } // Start the main thread // Skipping the int $0x80 thr.Start(new Pointer(pt_regs.ip + 2), newsp.Value); // There's no need to set eax for thr as they are zero by default.. return thr.Tid; }
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; }
// 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 UserPtr RoundDown(UserPtr stack_top) { return new UserPtr(stack_top.Value.ToUInt32() & ~3U); }
private static UserPtr[] PushCharArray(Process proc, ASCIIString[] arr, ref UserPtr stack_top) { var res = new UserPtr[arr.Length]; for (int i = 0; i < arr.Length; ++i) { // Include the terminator stack_top -= arr[i].Length + 1; res[i] = stack_top; if (stack_top.Write(proc, arr[i].GetByteString()) != 0) return null; } return res; }
private static int PushArgumentPointers(Process proc, UserPtr[] arr, ref UserPtr stack_top) { if (PushInt(proc, 0, ref stack_top) != 0) return -1; for (int i = arr.Length - 1; i >= 0; --i) { var p = arr[i]; if (PushInt(proc, p.Value.ToInt32(), ref stack_top) != 0) return -1; } return 0; }
//* return values: //* zero - success //* -EINVAL - start + len < 0, start is not page-aligned, //* "behavior" is not a valid value, or application //* is attempting to release locked or shared pages. //* -ENOMEM - addresses in the specified range are not currently //* mapped, or are outside the AS of the process. //* -EIO - an I/O error occurred while paging in data. //* -EBADF - map exists, but area maps something that isn't a file. //* -EAGAIN - a kernel resource was temporarily unavailable. private static int madviseDontNeed(Thread current, uint start, int len) { if (Arch.ArchDefinition.PageOffset(start) != 0 || len < 0) return -ErrorCode.EINVAL; var alignedLength = Arch.ArchDefinition.PageAlign((uint)len); var endPage = new UserPtr(start + alignedLength); current.Parent.Space.workingSet.Remove(current.Parent.Space, new UserPtr(start), endPage); return 0; }
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 mprotect(Thread current, UserPtr addr, int len, int prot) { if (len < 0) return -ErrorCode.EINVAL; if (Arch.ArchDefinition.PageOffset(addr.Value.ToUInt32()) != 0) return -ErrorCode.EINVAL; var space = current.Parent.Space; var nextAddr = addr.Value; var aligned_len = (int)Arch.ArchDefinition.PageAlign((uint)len); var r = space.UpdateAccessRightRange(addr.Value, aligned_len, ProtToAccessFlag(prot)); if (!r) { return -ErrorCode.EINVAL; } if (!space.SanityCheck()) { Arch.Console.Write("Sanity Check failed, after mprotect vaddr="); Arch.Console.Write(addr.Value.ToUInt32()); Arch.Console.Write(", len="); Arch.Console.Write(len); space.DumpAll(); Utils.Panic(); } return 0; }
public static int munmap(Thread current, UserPtr addr, int length) { if (length <= 0) return -ErrorCode.EINVAL; var space = current.Parent.Space; var alignedLength = Arch.ArchDefinition.PageAlign(length); //Arch.Console.Write("munmap:"); //Arch.Console.Write(addr.Value.ToInt32()); //Arch.Console.Write(" sz="); //Arch.Console.Write(length); //Arch.Console.WriteLine(); if (alignedLength <= 0) return -ErrorCode.EINVAL; return space.RemoveMapping(addr.Value, alignedLength); }
private static int PushInt(Process proc, int v, ref UserPtr stack_top) { stack_top -= sizeof(int); if (stack_top.Write(proc, v) != 0) return -1; return 0; }
public static int mmap2(Thread current, UserPtr addr, int length, int prot, int flags, int fd, int pgoffset) { Contract.Requires(current.Parent == current.Parent.Space.GhostOwner); Pointer targetAddr = new Pointer(Arch.ArchDefinition.PageAlign(addr.Value.ToUInt32())); //Arch.Console.Write("mmap2:"); //Arch.Console.Write(addr.Value.ToInt32()); //Arch.Console.Write(" sz="); //Arch.Console.Write(length); //Arch.Console.Write(" prot="); //Arch.Console.Write(prot); //Arch.Console.WriteLine(); var proc = current.Parent; var space = proc.Space; Contract.Assert(proc == space.GhostOwner); if ((flags & MAP_FIXED) == 0) { if (targetAddr == Pointer.Zero || space.ContainRegion(targetAddr, length)) targetAddr = space.FindFreeRegion(length); } else if (Arch.ArchDefinition.PageOffset(addr.Value.ToInt32()) != 0) { return -ErrorCode.EINVAL; } targetAddr = new Pointer(Arch.ArchDefinition.PageIndex(targetAddr.ToUInt32())); if (targetAddr == Pointer.Zero || length == 0) return -ErrorCode.EINVAL; File file = null; GenericINode inode = null; if ((flags & MAP_ANONYMOUS) == 0) { file = proc.LookupFile(fd); if (file == null) return -ErrorCode.EBADF; inode = file.inode; } int memorySize = Arch.ArchDefinition.PageAlign(length); // fix for code contract if (length > memorySize) length = memorySize; if ((file != null && length == 0) || length < 0) return -ErrorCode.EINVAL; if (file == null) { pgoffset = 0; length = 0; } // // Be careful for shared mapping -- which could be a shared memory region coming from Linux. // In this case we'll need to (1) call mmap() in the shadow process to obtain a valid mapping // (2) when a page fault happens, grabs the physical page from linux. // if ((flags & MAP_SHARED) != 0 && SharedWithLinux(inode)) { // Don't know how to deal with it... if (addr != UserPtr.Zero) return -ErrorCode.EINVAL; var vaddr = Arch.IPCStubs.linux_sys_alien_mmap2(current.Parent.helperPid, addr.Value, length, prot, flags, inode.LinuxFd, pgoffset); if (vaddr > AddressSpace.KERNEL_OFFSET) return -ErrorCode.EINVAL; switch (inode.kind) { case GenericINode.INodeKind.BinderSharedINodeKind: case GenericINode.INodeKind.AshmemINodeKind: case GenericINode.INodeKind.ScreenBufferINodeKind: inode.AlienSharedMemoryINode.vaddrInShadowProcess = new Pointer(vaddr); break; default: // UNIMPLEMENTED... let's return EINVAL to make sure we can catch it. return -ErrorCode.EINVAL; } } var r = space.AddMapping(ProtToAccessFlag(prot), flags, file, (uint)pgoffset * Arch.ArchDefinition.PageSize, length, targetAddr, memorySize); if (r < 0) return r; // // HACK for binder IPC // if (inode != null && inode.kind == GenericINode.INodeKind.BinderINodeKind) { proc.binderVMStart = new UserPtr(targetAddr); proc.binderVMSize = length; } return targetAddr.ToInt32(); }
private static int PushProgramHeaderAndAuxliraryVectors(Process proc, File file, ELF32Header eh, ref UserPtr stackTop) { var programHeaderLength = eh.NumOfProgramHeader * eh.ProgramHeaderSize; var buf = new byte[programHeaderLength]; uint pos = eh.ProgramHeaderOffest; if (file.Read(buf, ref pos) != programHeaderLength) return -ErrorCode.ENOMEM; stackTop -= programHeaderLength; UserPtr ph_ptr = stackTop; if (ph_ptr.Write(proc, buf) != 0) return -ErrorCode.ENOMEM; // align stackTop = UserPtr.RoundDown(stackTop); var aux_vector = new uint[LengthOfAuxVector]; aux_vector[0] = AT_PHDR; aux_vector[1] = ph_ptr.Value.ToUInt32(); aux_vector[2] = AT_ENTRY; aux_vector[3] = eh.EntryPoint; aux_vector[4] = AT_PHNUM; aux_vector[5] = eh.NumOfProgramHeader; aux_vector[6] = 0; aux_vector[7] = 0; var auxVectorSize = sizeof(uint) * LengthOfAuxVector; stackTop -= auxVectorSize; if (stackTop.Write(proc, aux_vector) != 0) return -ErrorCode.ENOMEM; return 0; }
private static int StatAt64(Thread current, UserPtr filenamePtr, UserPtr buf, bool followSymlink) { var proc = current.Parent; int err; filenamePtr.ReadString(current, Globals.LinuxIPCBuffer); if (followSymlink) { err = Arch.IPCStubs.linux_sys_stat64(proc.helperPid); } else { err = Arch.IPCStubs.linux_sys_lstat64(proc.helperPid); } if (err != 0) return err; if (buf.Write(current, new Pointer(Globals.LinuxIPCBuffer.Location), SIZE_OF_STAT64) != 0) return -ErrorCode.EFAULT; return 0; }
private static Pointer FindShadowAddr(Thread current, UserPtr uaddr) { var r = current.Parent.Space.Find(uaddr.Value); if (r == null) return Pointer.Zero; var f = r.BackingFile; var shm_inode = f.inode.AlienSharedMemoryINode; if (shm_inode != null) return shm_inode.vaddrInShadowProcess + (uaddr.Value - r.StartAddress); else return Pointer.Zero; }
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; }
// // We do sync read for this one, since it's simpler.. // public static Process CreateProcess(ASCIIString path, ASCIIString[] argv, ASCIIString[] envp, AndroidApplicationInfo appInfo) { var proc = new Process(path, appInfo); Utils.Assert(!proc.Space.impl._value.isInvalid); uint addr; int workspace_fd; uint workspace_size; proc.helperPid = Arch.IPCStubs.linux_sys_take_helper(out addr, out workspace_fd, out workspace_size); if (proc.helperPid < 0) { Arch.Console.WriteLine("CreateProcess: cannot get helper"); return null; } proc.ShadowBinderVMStart = addr; ErrorCode ec; var inode = Arch.ArchFS.Open(proc.helperPid, path, 0, 0, out ec); if (inode == null) { Arch.Console.WriteLine("CreateProcess: cannot open file"); return null; } var stack_top = new UserPtr(INITIAL_STACK_LOCATION); // 4M Initial stack var stack_size = 4096 * Arch.ArchDefinition.PageSize; proc.Space.AddStackMapping(stack_top, stack_size); stack_top += stack_size; var augmented_envp = CreateEnvpArrayWithWorkspace(envp, proc, workspace_fd, workspace_size); var envp_ptr = PushCharArray(proc, augmented_envp, ref stack_top); if (envp_ptr == null) { Arch.Console.WriteLine("CreateProcess: Push envp failed"); return null; } var argv_ptr = PushCharArray(proc, argv, ref stack_top); if (argv_ptr == null) { Arch.Console.WriteLine("CreateProcess: Push argv failed"); return null; } stack_top = UserPtr.RoundDown(stack_top); // Parse the ELF file, which might push additional info on to the stack // (i.e., aux vectors when the ELF is dynamically linked) var file = new File(proc, inode, FileFlags.ReadWrite, 0); int ret = ELF32Header.Parse(proc.helperPid, file, proc, ref stack_top); if (ret != 0) { Arch.Console.WriteLine("CreateProcess: Parse ELF file failed"); return null; } //%esp The stack contains the arguments and environment: // 0(%esp) argc // 4(%esp) argv[0] // ... // (4*argc)(%esp) NULL // (4*(argc+1))(%esp) envp[0] // ... // NULL if (PushArgumentPointers(proc, envp_ptr, ref stack_top) != 0) return null; if (PushArgumentPointers(proc, argv_ptr, ref stack_top) != 0) return null; if (PushInt(proc, argv_ptr.Length, ref stack_top) != 0) return null; // Stdio var file_stdout = File.CreateStdout(proc); Contract.Assume(proc.Files.IsAvailableFd(Process.STDOUT_FD)); proc.InstallFd(Process.STDOUT_FD, file_stdout); var file_stderr = File.CreateStdout(proc); Contract.Assume(proc.Files.IsAvailableFd(Process.STDERR_FD)); proc.InstallFd(Process.STDERR_FD, file_stderr); var mainThread = Thread.Create(proc); if (appInfo != null) { var p = appInfo.ToParcel(); Globals.LinuxIPCBuffer.CopyFrom(0, p); Arch.IPCStubs.WriteAppInfo(proc.helperPid, p.Length); } // Start the main thread mainThread.Start(new Pointer(proc.EntryPoint), stack_top.Value); return proc; }
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; }
private static int Wake(Thread current, UserPtr uaddr, int flags, int nr_wake, uint bitset) { if (bitset == 0) return -ErrorCode.EINVAL; var space = current.Parent.Space; int ret = 0; //Arch.Console.Write("Futex_wake: thr="); //Arch.Console.Write(current.Tid); //Arch.Console.Write(" uaddr="); //Arch.Console.Write(uaddr.Value.ToUInt32()); //Arch.Console.Write(" nr_wake="); //Arch.Console.Write(nr_wake); //Arch.Console.WriteLine(); FutexCompletionEntry q; // XXX: For simplicity (right now), we scan through the whole completion queue for (var p = Globals.FutexLists.nextFutex; p != Globals.FutexLists && ret < nr_wake; p = q) { q = p.nextFutex; //Arch.Console.Write("wake_loop: uaddr="); //Arch.Console.Write(p.uaddr.Value.ToUInt32()); //Arch.Console.Write(" tid="); //Arch.Console.Write(p.thr.Tid); //Arch.Console.WriteLine(); if (!(p.Space == space && p.uaddr == uaddr && (p.bitset & bitset) != 0)) continue; ++ret; WakeUp(p, true, 0); } return ret; }