/*
         * Create a new memory region in the address space.
         *
         * If there are any overlaps between the current address space and the requested one,
         * this function will unamp the overlapped portions of the address space before
         * mapping in the new memory region.
         *
         * Several clients, including the dynamic linker relies on this feature. See mmap(2)
         * for details.
         *
         * This function requires vaddr and memorySize are aligned to the page boundary.
         */
        internal int AddMapping(uint access, int flags, File file, uint fileOffset, int fileSize, Pointer vaddr, int memorySize)
        {
            Contract.Requires(file == null || file.GhostOwner == GhostOwner);
            Contract.Requires(0 <= fileSize && fileSize <= memorySize);
            Contract.Requires(file == null || fileSize > 0);
            Contract.Requires(file != null || (fileSize == 0 && fileOffset == 0));
            Contract.Ensures(Brk == Contract.OldValue(Brk));

            if (memorySize <= 0 || Arch.ArchDefinition.PageOffset(memorySize) != 0)
                return -ErrorCode.EINVAL;

            var diff = Arch.ArchDefinition.PageOffset(vaddr.ToUInt32());
            if (diff != 0)
                return -ErrorCode.EINVAL;

            var r = RemoveMapping(vaddr, memorySize);
            if (r != 0)
            {
                return r;
            }

            var newRegion = new MemoryRegion(GhostOwner, access, flags, file, fileOffset, fileSize, vaddr, memorySize, false);
            Insert(newRegion);
            return 0;
        }
        internal int GetUnusedFd()
        {
            Contract.Ensures(IsAvailableFd(Contract.Result<int>()));

            var _this = this;
            var size = descriptors.Length;
            var i = finger;
            while (i < size)
            {
                if (IsAvailableFd(i))
                {
                    UpdateFinger(i);
                    return i;
                }
                ++i;
            }

            var new_descriptors = new File[2 * size];
            for (var j = 0; j < size; ++j)
            {
                new_descriptors[i] = descriptors[i];
            }

            for (var j = size; j < 2 * size; ++j)
            {
                new_descriptors[i] = null;
            }

            descriptors = new_descriptors;

            // Proven by Dafny
            Contract.Assume(IsAvailableFd(size));
            UpdateFinger(size);
            return size;
        }
        internal void Add(int fd, File file)
        {
            Contract.Requires(IsAvailableFd(fd));
            Contract.Requires(file != null && file.GhostOwner == GhostOwner);
            Contract.Ensures(IsValidFd(fd));

            descriptors[fd] = file;
        }
Example #4
0
        internal void InstallFd(int fd, File file)
        {
            Contract.Requires(file != null);
            Contract.Requires(file.GhostOwner == this);
            Contract.Requires(Files.IsAvailableFd(fd));

            Files.Add(fd, file);
        }
Example #5
0
        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 MemoryRegion(Process owner, uint access, int flags, File file, uint fileOffset, int fileSize, Pointer vaddr, int size, bool isFixed)
        {
            Contract.Requires(file == null || file.GhostOwner == owner);
            Contract.Ensures(GhostOwner == owner);

            this.Access = access;
            this.Flags = flags;
            this.BackingFile = file;
            this.FileOffset = fileOffset;
            this.FileSize = fileSize;
            this.StartAddress = vaddr;
            this.Size = size;
            this.Next = null;
            this.IsFixed = isFixed;
            this.GhostOwner = owner;

            if (file != null)
                file.inode.IncreaseRefCount();
        }
Example #7
0
        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;
        }
Example #8
0
        private static int MapInSegments(File file, Process proc, ELF32Header eh)
        {
            Contract.Requires(file != null && file.GhostOwner == proc);
            Contract.Requires(proc.Space.GhostOwner == proc);

            var buf = new byte[ELF32ProgramHeader.Size];

            var ph = new ELF32ProgramHeader();
            // At this point we need to map in all stuff in PT_LOAD
            for (var i = 0; i < eh.NumOfProgramHeader; ++i)
            {
                var pos = (uint)(eh.ProgramHeaderOffest + eh.ProgramHeaderSize * i);
                if (file.Read(buf, ref pos) != buf.Length)
                    return -ErrorCode.EINVAL;

                ph = ELF32ProgramHeader.Read(buf);

                var size = ph.FileSize > ph.MemorySize ? ph.FileSize : ph.MemorySize;

                if (ph.type != ELF32ProgramHeader.PT_LOAD)
                    continue;

                // Round address to page boundary

                var diff = Arch.ArchDefinition.PageOffset(ph.vaddr);
                var vaddr = new Pointer(ph.vaddr);
                var offset = ph.offset;
                var memSize = (int)Arch.ArchDefinition.PageAlign((uint)ph.MemorySize);
                var fileSize = ph.FileSize;

                if (diff < 0 || ph.offset < diff || fileSize + diff > file.inode.Size || fileSize <= 0 || memSize <= 0)
                    return -ErrorCode.EINVAL;

                vaddr -= diff;
                offset -= (uint)diff;
                fileSize += diff;

                if (fileSize > memSize)
                    fileSize = memSize;

                if (proc.Space.AddMapping(ph.ExpressOSAccessFlag, 0, file, offset, fileSize, vaddr, memSize) != 0)
                    return -ErrorCode.ENOMEM;

                // Update brk

                var segmentEnd = (vaddr + memSize).ToUInt32();
                if (segmentEnd > proc.Space.Brk)
                {
                    proc.Space.InitializeBrk(segmentEnd);
                }
            }
            return 0;
        }
Example #9
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;
        }
Example #10
0
        private static ASCIIString[] CreateEnvpArrayWithWorkspace(ASCIIString[] envp, Process proc, int workspace_fd, uint workspace_size)
        {
            var res = new ASCIIString[envp.Length + 1];
            for (int i = 0; i < envp.Length; ++i)
                res[i] = envp[i];

            var inode = new Arch.ArchINode(workspace_fd, workspace_size, proc.helperPid);

            var file = new File(proc, inode, FileFlags.ReadOnly, 0);

            var fd = proc.GetUnusedFd();
            proc.InstallFd(fd, file);

            var s = "ANDROID_PROPERTY_WORKSPACE=" + fd.ToString() + "," + workspace_size.ToString();
            res[envp.Length] = new ASCIIString(s);

            return res;
        }
Example #11
0
        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;
        }
Example #12
0
        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;
        }
Example #13
0
        /*
         * Write a segment buffer.
         *
         * The buffer itself is passed as a reference, because some inode might take the ownership
         * of the buffer and put it as a part of its completion. In this case the buf is set to empty
         */
        internal int Write(Thread current, ref Arch.ExceptionRegisters regs, ref ByteBufferRef buf, int len, uint pos, File file)
        {
            switch (kind)
            {
                case INodeKind.ConsoleINodeKind:
                    {
                        uint dummy = 0;
                        return ConsoleINode.WriteImpl(current, buf, len, ref dummy);
                    }
                case INodeKind.ArchINodeKind:
                case INodeKind.SocketINodeKind:
                    return ArchINode.ArchWrite(current, ref regs, ref buf, len, pos, file);

                case INodeKind.SecureFSINodeKind:
                    return SFSINode.SFSWrite(current, ref regs, buf, len, pos, file);
            }
            return -ErrorCode.EINVAL;
        }
Example #14
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;
        }
Example #15
0
        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;
        }
Example #16
0
        public static void HandleSocketCompletion(SocketCompletion c, int ret)
        {
            var current = c.thr;
            if (ret < 0)
            {
                current.ReturnFromCompletion(ret);
                return;
            }

            var proc = current.Parent;

            var inode = new SocketINode(ret, proc.helperPid);
            var file = new File(proc, inode, FileFlags.ReadWriteMask, 0);

            var fd = proc.GetUnusedFd();
            proc.InstallFd(fd, file);
            current.ReturnFromCompletion(fd);
        }
Example #17
0
        private static int FindInterpreter(File file, ELF32Header eh, ref ELF32ProgramHeader ret)
        {
            var buf = new byte[ELF32ProgramHeader.Size];

            uint pos = 0;
            ushort i = 0;

            while (i < eh.NumOfProgramHeader)
            {
                pos = (uint)(eh.ProgramHeaderOffest + eh.ProgramHeaderSize * i);
                if (file.Read(buf, ref pos) != ELF32ProgramHeader.Size)
                    return -ErrorCode.EINVAL;

                ret = ELF32ProgramHeader.Read(buf);

                if (ret.type == ELF32ProgramHeader.PT_INTERP)
                    break;

                ++i;
            }
            return i == eh.NumOfProgramHeader ? -ErrorCode.ENOENT : 0;
        }
Example #18
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;
        }