/* * 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; }
// Create an empty user-space memory region // reserve the first page as well as the kernel space public static MemoryRegion CreateUserSpaceRegion(Process owner) { Contract.Ensures(Contract.Result<MemoryRegion>().GhostOwner == owner); var r = new MemoryRegion(owner, 0, 0, null, 0, 0, Pointer.Zero, Arch.ArchDefinition.PageSize, true); var r1 = new MemoryRegion(owner, 0, 0, null, 0, 0, new Pointer(AddressSpace.KERNEL_OFFSET), AddressSpace.KERNEL_SIZE, true); r.Next = r1; return r; }
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(); }
private void RemoveMappingCenter(Pointer vaddr, int size, ref MemoryRegion prev, out int ret, out bool changed) { Contract.Ensures(Brk == Contract.OldValue(Brk)); changed = false; var r = prev.Next; var end = vaddr + size; while (r != null && !r.IsFixed && r.End <= end) { changed = true; RemoveNode(prev, r); r = prev.Next; } if (r != null && r.End <= end && r.IsFixed) { ret = -ErrorCode.EINVAL; return; } if (r == null || r.StartAddress >= end) { ret = 0; return; } ret = 1; return; }
void InsertOrMerge(MemoryRegion prev, MemoryRegion r, MemoryRegion next) { Contract.Ensures(Brk == Contract.OldValue(Brk)); if (MemoryRegion.CanMerge(prev, r)) { prev.Expand(r); return; } InsertNode(prev, r); TryMergeWithNext(r); }
void InsertNode(MemoryRegion prev, MemoryRegion r) { Contract.Ensures(Brk == Contract.OldValue(Brk)); r.Next = prev.Next; prev.Next = r; }
void Insert(MemoryRegion r) { Contract.Requires(r != null && r.GhostOwner == GhostOwner); Contract.Ensures(Brk == Contract.OldValue(Brk)); var h = Head.Next; var prev = Head; while (h != null && h.End <= r.StartAddress) { prev = h; h = h.Next; } InsertOrMerge(prev, r, h); return; }
internal static bool CanMerge(MemoryRegion prev, MemoryRegion next) { var same_inode = (prev.BackingFile == next.BackingFile || (prev.BackingFile != null && next.BackingFile != null && prev.BackingFile.inode == next.BackingFile.inode)); return same_inode && prev.Access == next.Access && prev.End == next.StartAddress && (prev.BackingFile == null || prev.FileEnd == next.FileOffset); }
void UpdateAccessRights(MemoryRegion r, uint newaccess) { r.UpdateAccessRights(this, newaccess); }
// // Separate region into two. It returns the rightmost part of the region // MemoryRegion Split(MemoryRegion r, int offset) { Contract.Requires(r.BackingFile == null || r.BackingFile.GhostOwner == r.GhostOwner); //Contract.Ensures(Contract.Result<MemoryRegion>().BackingFile.GhostOwner == Contract.Result<MemoryRegion>().GhostOwner); Contract.Ensures(Brk == Contract.OldValue(Brk)); MemoryRegion next; if (offset >= r.FileSize) { next = new MemoryRegion(r.GhostOwner, r.Access, r.Flags, null, 0, 0, r.StartAddress + offset, r.Size - offset, r.IsFixed); } else { next = new MemoryRegion(r.GhostOwner, r.Access, r.Flags, r.BackingFile, (uint)(r.FileOffset + (uint)offset), (int)(r.FileSize - offset), r.StartAddress + offset, r.Size - offset, r.IsFixed); } r.CutRight(r.Size - offset); InsertNode(r, next); return next; }
void InsertNode(MemoryRegion prev, MemoryRegion r) { r.Next = prev.Next; prev.Next = r; }
private static Pointer ToShadowProcessAddress(Pointer faultAddress, MemoryRegion region) { var f = region.BackingFile; Pointer vaddr = Pointer.Zero; switch (f.inode.kind) { case GenericINode.INodeKind.BinderSharedINodeKind: case GenericINode.INodeKind.ScreenBufferINodeKind: case GenericINode.INodeKind.AshmemINodeKind: vaddr = f.inode.AlienSharedMemoryINode.vaddrInShadowProcess; break; default: Arch.ArchDefinition.Panic(); break; } return vaddr + (faultAddress - region.StartAddress); }
private static bool IsAlienSharedRegion(MemoryRegion region) { if ((region.Flags & Memory.MAP_SHARED) == 0) return false; if (region.BackingFile == null) return false; return region.BackingFile.inode.kind == GenericINode.INodeKind.BinderSharedINodeKind || region.BackingFile.inode.kind == GenericINode.INodeKind.AshmemINodeKind || region.BackingFile.inode.kind == GenericINode.INodeKind.ScreenBufferINodeKind; }
internal void Expand(MemoryRegion r) { Size += r.Size; if (BackingFile != null) FileSize += r.FileSize; }
private void RemoveMappingLeft(Pointer vaddr, int size, out int ret, out bool changed, out MemoryRegion prev) { Contract.Ensures(Brk == Contract.OldValue(Brk)); prev = Head; var r = prev.Next; var end = vaddr + size; var oldBrk = Brk; if (Head.OverlappedInt(vaddr, size)) { ret = -ErrorCode.EINVAL; changed = false; return; } while (r != null && r.End <= vaddr) { prev = r; r = r.Next; } // No overlaps if (r == null || r.StartAddress >= end) { ret = 0; changed = false; return; } if (r.IsFixed) { ret = -ErrorCode.EINVAL; changed = false; return; } if (r.StartAddress < vaddr) { if (end < r.End) { var offset = vaddr - r.StartAddress; var middleRegion = Split(r, offset); } else { r.CutRight(r.End - vaddr); } prev = r; r = r.Next; ret = 1; changed = true; Contract.Assert(Brk == oldBrk); return; } ret = 1; changed = false; return; }
void RemoveNode(MemoryRegion prev, MemoryRegion r) { Contract.Ensures(Brk == Contract.OldValue(Brk)); prev.Next = r.Next; }
void InsertOrMerge(MemoryRegion prev, MemoryRegion r, MemoryRegion next) { if (MemoryRegion.CanMerge(prev, r)) { prev.Expand(r); return; } InsertNode(prev, r); TryMergeWithNext(r); }
bool TryMergeWithNext(MemoryRegion r) { Contract.Ensures(Brk == Contract.OldValue(Brk)); var next = r.Next; if (next != null && MemoryRegion.CanMerge(r, next)) { RemoveNode(r, next); r.Expand(next); return true; } else { return false; } }
void RemoveNode(MemoryRegion prev, MemoryRegion r) { prev.Next = r.Next; }
bool TryMergeWithNext(MemoryRegion r) { var next = r.Next; if (next != null && MemoryRegion.CanMerge(r, next)) { RemoveNode(r, next); r.Expand(next); return true; } else { return false; } }
public bool Overlapped(MemoryRegion rhs) { return OverlappedInt(rhs.StartAddress, rhs.Size); }