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; }
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); }
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); }