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; }
public File(Process owner, GenericINode inode, int flags, int mode) { Contract.Ensures(GhostOwner == owner); this.inode = inode; this.flags = flags; this.mode = mode; this.position = 0; this.GhostOwner = owner; inode.IncreaseRefCount(); }
internal static void HandleOpenFileCompletion(OpenFileCompletion c, int linux_fd, int size) { var current = c.thr; var proc = current.Parent; GenericINode inode = null; int ret = linux_fd; if (ret < 0) { c.Dispose(); current.ReturnFromCompletion(ret); return; } switch (c.fileKind) { case GenericINode.INodeKind.ArchINodeKind: inode = new Arch.ArchINode(linux_fd, (uint)size, proc.helperPid); break; case GenericINode.INodeKind.SecureFSINodeKind: inode = SecureFS.HandleOpenFileCompletion(c, linux_fd, size, ref ret); break; default: break; } if (inode != null) { var file = new File(proc, inode, c.flags, c.mode); ret = proc.GetUnusedFd(); proc.InstallFd(ret, file); } c.Dispose(); current.ReturnFromCompletion(ret); return; }
private static bool SharedWithLinux(GenericINode inode) { return inode.kind == GenericINode.INodeKind.BinderSharedINodeKind || inode.kind == GenericINode.INodeKind.AshmemINodeKind || inode.kind == GenericINode.INodeKind.ScreenBufferINodeKind; }
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); }
public static int Open(Thread current, ref Arch.ExceptionRegisters regs, UserPtr filenamePtr, int flags, int mode) { // TODO: Deal with current path var filenameBuf = new byte[PATH_MAX]; var ret = filenamePtr.ReadString(current, filenameBuf); var proc = current.Parent; int fd = 0; GenericINode inode = null; var startTime = Arch.NativeMethods.l4api_get_system_clock(); if (Util.ByteStringCompare(filenameBuf, IPCFilename.GetByteString()) == 0) { fd = proc.GetUnusedFd(); inode = BinderINode.Instance; } else if (Util.ByteStringCompare(filenameBuf, AshmemFileName.GetByteString()) == 0) { var linux_fd = Arch.ArchFS.OpenAndReturnLinuxFd(current.Parent.helperPid, new ASCIIString(filenameBuf), flags, mode); if (linux_fd < 0) { return(linux_fd); } inode = new AshmemINode(linux_fd, current.Parent.helperPid); fd = proc.GetUnusedFd(); } else if (SecureFS.IsSecureFS(current, filenameBuf)) { var completion = SecureFS.OpenAndReadPagesAsync(current, filenameBuf, flags, mode); if (completion == null) { return(-ErrorCode.ENOMEM); } Globals.CompletionQueue.Enqueue(completion); current.SaveState(ref regs); current.AsyncReturn = true; return(0); } else { var filename_len = ret; var completion = Arch.ArchFS.OpenAndGetSizeAsync(current, filenameBuf, flags, mode); if (completion == null) { return(-ErrorCode.ENOMEM); } Globals.CompletionQueue.Enqueue(completion); current.SaveState(ref regs); current.AsyncReturn = true; return(0); } if (fd > 0) { var file = new File(proc, inode, flags, mode); proc.InstallFd(fd, file); } if (SyscallProfiler.Enable) { var endTime = Arch.NativeMethods.l4api_get_system_clock(); SyscallProfiler.AccountOpen((int)inode.kind, (long)(endTime - startTime)); } return(fd); }
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 bool SharedWithLinux(GenericINode inode) { return(inode.kind == GenericINode.INodeKind.BinderSharedINodeKind || inode.kind == GenericINode.INodeKind.AshmemINodeKind || inode.kind == GenericINode.INodeKind.ScreenBufferINodeKind); }