Ejemplo n.º 1
0
        public static void HandlePageFault(Process process, uint faultType, Pointer faultAddress, Pointer faultIP, out Pointer physicalPage, out uint permission)
        {
            // Object invariants of Process
            Contract.Assume(process.Space.GhostOwner == process);
            Contract.Assume(process.Space.Head.GhostOwner == process);

            // Never map page 0
            if (faultAddress.ToUInt32() < Arch.ArchDefinition.PageSize)
            {
                physicalPage = Pointer.Zero;
                permission   = MemoryRegion.FALUT_NONE;
                return;
            }

            SyscallProfiler.EnterPageFault();
            var space  = process.Space;
            var region = space.Find(faultAddress);

            if (region != null && (faultType & region.Access) != 0)
            {
                /*
                 * Check whether the kernel has allocated a page for this address,
                 * which might be the case due to UserPtr.Read() / UserPtr.Write().
                 */
                var mapped_in_page = space.UserToVirt(new UserPtr(faultAddress));

                if (mapped_in_page != Pointer.Zero)
                {
                    physicalPage = PageIndex(mapped_in_page);
                    permission   = region.Access & MemoryRegion.FAULT_MASK;
                    return;
                }

                // If the page is a shared page from Linux, we'll need to ask linux to grab the page
                // Otherwise let's just allocate a fresh one.

                var shared_memory_region         = IsAlienSharedRegion(region);
                var ghost_page_from_fresh_memory = false;

                ByteBufferRef buf;
                if (shared_memory_region)
                {
                    buf = Globals.LinuxMemoryAllocator.GetUserPage(process, faultType, ToShadowProcessAddress(faultAddress, region));
                    if (!buf.isValid)
                    {
                        Arch.Console.WriteLine("pager: cannot map in alien page.");
                        space.DumpAll();
                        physicalPage = Pointer.Zero;
                        permission   = MemoryRegion.FALUT_NONE;
                        return;
                    }
                }
                else
                {
                    buf = Globals.PageAllocator.AllocPage();

                    ghost_page_from_fresh_memory = true;

                    if (!buf.isValid)
                    {
                        Arch.Console.WriteLine("Cannot allocate new pages");
                        Utils.Panic();
                    }

                    if (region.BackingFile != null)
                    {
                        var  rel_pos = (PageIndex(faultAddress) - region.StartAddress);
                        uint pos     = (uint)((ulong)rel_pos + region.FileOffset);

                        var readSizeLong = region.FileSize - rel_pos;
                        if (readSizeLong < 0)
                        {
                            readSizeLong = 0;
                        }
                        else if (readSizeLong > Arch.ArchDefinition.PageSize)
                        {
                            readSizeLong = Arch.ArchDefinition.PageSize;
                        }

                        int readSize = (int)readSizeLong;

                        Contract.Assert(region.BackingFile.GhostOwner == process);

                        var r = region.BackingFile.Read(buf, 0, readSize, ref pos);
                        if (r < 0)
                        {
                            r = 0;
                        }

                        Utils.Assert(r <= Arch.ArchDefinition.PageSize);

                        if (r < Arch.ArchDefinition.PageSize)
                        {
                            buf.ClearAfter(r);
                        }
                    }
                    else
                    {
                        buf.Clear();
                    }
                }

                Contract.Assert(shared_memory_region ^ ghost_page_from_fresh_memory);

                var page = new Pointer(buf.Location);
                space.AddIntoWorkingSet(new UserPtr(PageIndex(faultAddress)), page);

                SyscallProfiler.ExitPageFault();
                physicalPage = page;
                permission   = region.Access & MemoryRegion.FAULT_MASK;
                return;
            }
            else
            {
                /*
                 * TODO: mmap2 enables the application requests an automatically expandable
                 * region (e.g., a stack)
                 *
                 * The feature doesn't seem to be actively used by the applications, since
                 * both the C runtime and the pthread library initializes stack explicitly.
                 *
                 * The feature is currently unimplemented.
                 */
            }

            physicalPage = Pointer.Zero;
            permission   = MemoryRegion.FALUT_NONE;
            return;
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
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);
        }