/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: IoMemory.cs // using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using Microsoft.Singularity.Memory; #if SINGULARITY_PROCESS using Microsoft.Singularity.V1.Services; using System.Diagnostics; #endif // SINGULARITY_PROCESS using PageType = System.GCs.PageType; namespace Microsoft.Singularity.Io { [CLSCompliant(false)] public sealed class IoMemory { private enum MemoryType { RegularPages, // We refer to memory allocated from general-purpose memory IOMemory, // We refer to a block allocated from the IOMemory pool VirtWrapper, // We wrap a range of virtual addresses that we didn't alloc PhysMapped, // We wrap a range of physical addresses that we mapped PhysWrapper, // We wrap a range of physical addresses that we didn't map } private readonly PhysicalAddress dataPhys; private readonly unsafe byte * data; private readonly int bytes; private readonly MemoryType type; private bool readable; private bool writable; ////////////////////////////////////////////////////////////////////////////// // #if SINGULARITY_PROCESS internal const byte PageBits = 12; internal const uint PageSize = 1 << PageBits; internal const uint PageMask = PageSize - 1; [Inline] internal static UIntPtr PagePad(UIntPtr addr) { return ((addr + PageMask) & ~PageMask); } #endif // Request a mapping to physical memory static public IoMemory MapPhysicalMemory(UIntPtr physAddr, UIntPtr bytes, bool readable, bool writable) { DebugStub.Assert(physAddr != UIntPtr.Zero); #if SINGULARITY_KERNEL UIntPtr virtAddr = MemoryManager.KernelMapPhysicalMemory( new PhysicalAddress((ulong)physAddr), bytes); DebugStub.Assert(virtAddr != UIntPtr.Zero); return new IoMemory(MemoryType.PhysMapped, new PhysicalAddress(physAddr), virtAddr, (int)bytes, readable, writable); #elif SINGULARITY_PROCESS UIntPtr virtAddr = DeviceService.MapPhysicalRange((ulong)physAddr, (uint)bytes, readable, writable); DebugStub.Assert(virtAddr != UIntPtr.Zero); return new IoMemory(MemoryType.PhysMapped, new PhysicalAddress(physAddr), virtAddr, (int)bytes, readable, writable); #endif } #if SINGULARITY_KERNEL // // Kernel-only: just wrap a range of memory in an IoMemory for convenience // static public IoMemory Wrap(UIntPtr virtAddr, UIntPtr bytes, bool readable, bool writable) { return new IoMemory(MemoryType.VirtWrapper, virtAddr, (int)bytes, readable, writable); } // // Kernel-only: Allocate fixed memory from the user range // static internal IoMemory AllocateUserFixed(UIntPtr bytes, Process process, PageType type) { bytes = MemoryManager.PagePad(bytes); UIntPtr pages = MemoryManager.PagesFromBytes(bytes); UIntPtr addr = MemoryManager.UserAllocate(pages, process, 0, type); if (addr == UIntPtr.Zero) { return null; } return new IoMemory(MemoryType.RegularPages, addr, (int)bytes, true, true); } #endif // // Allocate virtually but not physically contiguous pages. The resulting // IoMemory object grants access to a number of bytes rounded up to // the nearest page boundary. // static public IoMemory AllocateFixed(UIntPtr bytes) { #if SINGULARITY_KERNEL return AllocateFixed(bytes, Thread.CurrentProcess, PageType.NonGC); #elif SINGULARITY_PROCESS int mybytes = (int)bytes; bytes = PagePad(bytes); UIntPtr addr = (UIntPtr)PageTableService.Allocate((uint)bytes); if (addr == UIntPtr.Zero) { return null; } return new IoMemory(MemoryType.RegularPages, addr, (int)bytes, true, true); #endif // SINGULARITY_PROCESS } // // Allocate virtually but not physically contiguous pages. The resulting // IoMemory object grants access only to the number of bytes requested // (possibly leaving inaccessible bytes at the end of the last page) // static public IoMemory AllocateRealFixed(UIntPtr bytes) { #if SINGULARITY_KERNEL return AllocateRealFixed(bytes, Thread.CurrentProcess, PageType.NonGC); #elif SINGULARITY_PROCESS int mybytes = (int)bytes; bytes = PagePad(bytes); UIntPtr addr = (UIntPtr)PageTableService.Allocate((uint)bytes); if (addr == UIntPtr.Zero) { return null; } return new IoMemory(MemoryType.RegularPages, addr, mybytes, true, true); #endif // SINGULARITY_PROCESS } #if SINGULARITY_KERNEL // // Kernel-only implementation of AllocateRealFixed // static internal IoMemory AllocateRealFixed(UIntPtr bytes, Process process, PageType type) { int mybytes = (int)bytes; UIntPtr pages = MemoryManager.PagesFromBytes(bytes); UIntPtr addr = MemoryManager.KernelAllocate(pages, process, 0, PageType.NonGC); #if DONT_DUMP unchecked { Tracing.Log(Tracing.Debug, "AllocateFixed -> [{0,8:x8}..{1,8:x8}]\n", addr, addr + bytes); } #endif if (addr == UIntPtr.Zero) { return null; } return new IoMemory(MemoryType.RegularPages, addr, (int)mybytes, true, true); } #endif // SINGULARITY_KERNEL #if SINGULARITY_KERNEL // // Kernel-only implementation of AllocateFixed // static internal IoMemory AllocateFixed(UIntPtr bytes, Process process, PageType type) { bytes = MemoryManager.PagePad(bytes); UIntPtr pages = MemoryManager.PagesFromBytes(bytes); UIntPtr addr = MemoryManager.KernelAllocate(pages, process, 0, PageType.NonGC); #if DONT_DUMP unchecked { Tracing.Log(Tracing.Debug, "AllocateFixed -> [{0,8:x8}..{1,8:x8}]\n", addr, addr + bytes); } #endif if (addr == UIntPtr.Zero) { return null; } return new IoMemory(MemoryType.RegularPages, addr, (int)bytes, true, true); } #endif // SINGULARITY_KERNEL // // Allocate PHYSICALLY contiguous memory. This allocates IO memory, // which is a scarce system resource when paging is enabled. // static public IoMemory AllocatePhysical(UIntPtr bytes) { return AllocatePhysical(bytes, 0); } static public IoMemory AllocatePhysical(UIntPtr bytes, UIntPtr alignment) { return AllocatePhysical(0, bytes, alignment); } static public IoMemory AllocatePhysical(UIntPtr limitAddr, UIntPtr bytes, UIntPtr alignment) { #if SINGULARITY_KERNEL bytes = MemoryManager.PagePad(bytes); UIntPtr addr = MemoryManager.AllocateIOMemory( limitAddr, bytes, alignment, Thread.CurrentProcess); #elif SINGULARITY_PROCESS bytes = PagePad(bytes); UIntPtr addr = (UIntPtr)PageTableService.AllocateIOMemory( (uint)limitAddr, (uint)bytes, (uint)alignment); #endif // SINGULARITY_PROCESS #if DONT_DUMP unchecked { Tracing.Log(Tracing.Debug, "AllocateFixed16MB -> [{0,8:x8}..{1,8:x8}]\n", addr, addr + bytes); } #endif if (addr == UIntPtr.Zero) { return null; } // IO memory is identity-mapped return new IoMemory(MemoryType.IOMemory, new PhysicalAddress((ulong)addr), addr, (int)bytes, true, true); } // // Allocate PHYSICALLY contiguous memory below the 16MB boundary. // This allocates IO memory, which is a scarce system resource when // paging is enabled. // static public IoMemory AllocatePhysBelow16MB(UIntPtr bytes) { return AllocatePhysBelow16MB(bytes); } static public IoMemory AllocatePhysBelow16MB(UIntPtr bytes, UIntPtr alignment) { return AllocatePhysical(0x1000000, bytes, alignment); } static public void Release(IoMemory range) { if (range == null || !range.readable) { throw new ArgumentNullException("Range is null"); } #if SINGULARITY_KERNEL Release(Thread.CurrentProcess, range); #elif SINGULARITY_PROCESS switch (range.type) { case MemoryType.RegularPages : PageTableService.Free(range.VirtualAddress, PagePad((UIntPtr)range.bytes)); break; case MemoryType.IOMemory : PageTableService.FreeIOMemory(range.VirtualAddress, PagePad((UIntPtr)range.bytes)); break; case MemoryType.PhysMapped : DeviceService.UnmapPhysicalRange((uint)range.VirtualAddress, (uint)(range.VirtualAddress + range.bytes)); break; case MemoryType.VirtWrapper : case MemoryType.PhysWrapper : // We do not own the memory; don't free it. break; default : DebugStub.Assert(false, "Unknown memory type in IoMemory.Release"); break; } range.readable = false; range.writable = false; #endif } #if SINGULARITY_KERNEL static internal void Release(Process process, IoMemory range) { if (range == null || !range.readable) { throw new ArgumentNullException("Range is null"); } switch (range.type) { case MemoryType.RegularPages : UIntPtr pages = MemoryManager.PagesFromBytes((UIntPtr)range.bytes); // // NOTE we allocate memory both in the kernel range and // the user range under different scenarios, so distinguish by // pointer value. // if (range.VirtualAddress > BootInfo.KERNEL_BOUNDARY) { MemoryManager.UserFree(range.VirtualAddress, pages, process); } else { MemoryManager.KernelFree(range.VirtualAddress, pages, process); } break; case MemoryType.PhysMapped : MemoryManager.KernelUnmapPhysicalMemory( range.VirtualAddress, range.VirtualAddress + range.bytes); break; case MemoryType.IOMemory : MemoryManager.FreeIOMemory( range.VirtualAddress, MemoryManager.PagePad((UIntPtr)range.bytes), process); break; case MemoryType.VirtWrapper : case MemoryType.PhysWrapper : // We do not own the memory; don't free it. break; default : DebugStub.Assert(false, "Unknown memory type in IoMemory.Release"); break; } range.readable = false; range.writable = false; } #endif // Sets or Gets the element at the given index. // //| public unsafe byte this[int index] { get { #if !DONT_CHECK_IO_BOUNDS if (index < 0 || index >= bytes) { Error.AccessOutOfRange(); } #endif return data[index]; } set { #if !DONT_CHECK_IO_BOUNDS if (index < 0 || index >= bytes) { Error.AccessOutOfRange(); } #endif data[index] = value; } } ////////////////////////////////////////////////////////////////////// // // Constructor for mappings onto physical memory private unsafe IoMemory(MemoryType type, PhysicalAddress physicalAddr, UIntPtr virtAddr, int bytes, bool readable, bool writable) { DebugStub.Assert((type == MemoryType.IOMemory) || (type == MemoryType.PhysWrapper) || (type == MemoryType.PhysMapped)); DebugStub.Assert(physicalAddr.Value != 0); DebugStub.Assert(virtAddr != 0); this.type = type; this.dataPhys = physicalAddr; this.data = (byte*)virtAddr; this.bytes = (int)bytes; this.readable = readable; this.writable = writable; } // Constructor for strictly virtual memory private unsafe IoMemory(MemoryType type, UIntPtr virtAddr, int bytes, bool readable, bool writable) { DebugStub.Assert((type == MemoryType.RegularPages) || (type == MemoryType.VirtWrapper)); DebugStub.Assert(virtAddr != 0); this.type = type; this.dataPhys = PhysicalAddress.Null; this.data = (byte*)virtAddr; this.bytes = (int)bytes; this.readable = readable; this.writable = writable; } public unsafe IoMemory AtOffset(uint byteOffset, int count) { return AtOffset(byteOffset, count, readable, writable); } public unsafe IoMemory AtOffset(uint byteOffset, int count, bool read, bool write) { #if !DONT_CHECK_IO_BOUNDS if (byteOffset + count > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif if ((type == MemoryType.RegularPages) || (type == MemoryType.VirtWrapper)) { // No physical address to worry about DebugStub.Assert(dataPhys.Value == 0); return new IoMemory(MemoryType.VirtWrapper, VirtualAddress + byteOffset, count, read, write); } else { DebugStub.Assert(dataPhys.Value != 0); // Update our physical address too PhysicalAddress newPhys = new PhysicalAddress(PhysicalAddress.Value + byteOffset); return new IoMemory(MemoryType.PhysWrapper, newPhys, VirtualAddress + byteOffset, count, read, write); } } // This address is likely useless without creating // another IoMemory object... public unsafe PhysicalAddress PhysicalAddress { [NoHeapAllocation] get { return dataPhys; } } public unsafe UIntPtr VirtualAddress { [NoHeapAllocation] get { return (UIntPtr)data; } } public int Length { [NoHeapAllocation] get { return bytes; } } public override string ToString() { return String.Format("32:{0,8:x8} -> {1,8:x8}[{2:x}]", (uint)VirtualAddress, PhysicalAddress.Value, (uint)bytes); } public static unsafe void Copy(IoMemory source, int byteSource, IoMemory destination, int byteDestination, int count) { byte* srcdataptr = source.data, destdataptr = destination.data; #if !DONT_CHECK_IO_BOUNDS if (byteSource + count > source.bytes || byteSource < 0 || byteDestination + count > destination.bytes || byteDestination < 0) { Error.AccessOutOfRange(); } #endif Buffer.MoveMemory(&destdataptr[byteDestination], &srcdataptr[byteSource], count * sizeof(byte)); } public unsafe string ReadAsciiZeroString(int byteOffset, int maxSize) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + maxSize > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif int len = 0; byte *dst = &data[byteOffset]; for (; len < maxSize && *dst != 0; len++) { dst++; } return String.StringCTOR(data, byteOffset, len); } public string ReadAsciiZeroString(int byteOffset) { #if !DONT_CHECK_IO_BOUNDS if (byteOffset > bytes) { Error.AccessOutOfRange(); } #endif return ReadAsciiZeroString(byteOffset, bytes - byteOffset); } [Inline] public unsafe byte Read8(int byteOffset) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif return data[byteOffset]; } [Inline] public unsafe ushort Read16(int byteOffset) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + sizeof(ushort) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif return *((ushort *)&data[byteOffset]); } [Inline] public unsafe uint Read32(int byteOffset) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + sizeof(uint) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif return *((uint *)&data[byteOffset]); } [Inline] public unsafe ulong Read64(int byteOffset) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + sizeof(ulong) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif return *((ulong *)&data[byteOffset]); } // -------------------------------------------------------------------- // Export non-exception throwing operations // // These are intended for use in the kernel on // NoHeapAllocation paths. The caller is expected to // check the result and/or know pre-conditions for the // I/O operation. #region NoHeapAllocation Read/Write operations #if SINGULARITY_KERNEL [Inline] [NoHeapAllocation] IoResult CheckRead(int byteOffset, int readBytes) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { return IoResult.ReadNotSupported; } if (byteOffset + readBytes > bytes || byteOffset < 0) { return IoResult.AccessOutOfRange; } #endif return IoResult.Success; } [Inline] [NoHeapAllocation] IoResult CheckWrite(int byteOffset, int writeBytes) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { return IoResult.WriteNotSupported; } if (byteOffset + writeBytes > bytes || byteOffset < 0) { return IoResult.AccessOutOfRange; } #endif return IoResult.Success; } [Inline] [NoHeapAllocation] public unsafe IoResult Read8NoThrow(int byteOffset, out byte value) { IoResult check = CheckRead(byteOffset, sizeof(byte)); if (IoResult.Success == check) { value = data[byteOffset]; } else { value = 0; } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Read16NoThrow(int byteOffset, out ushort value) { IoResult check = CheckRead(byteOffset, sizeof(ushort)); if (IoResult.Success == check) { value = *((ushort *)&data[byteOffset]); } else { value = 0; } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Read32NoThrow(int byteOffset, out uint value) { IoResult check = CheckRead(byteOffset, sizeof(uint)); if (IoResult.Success == check) { value = *((uint *)&data[byteOffset]); } else { value = 0; } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Read64NoThrow(int byteOffset, out ulong value) { IoResult check = CheckRead(byteOffset, sizeof(ulong)); if (IoResult.Success == check) { value = *((ulong *)&data[byteOffset]); } else { value = 0; } return check; } [NoHeapAllocation] public unsafe IoResult Read8NoThrow(int byteOffset, [In, Out] byte[] buffer, int offset, int count) { IoResult check = CheckRead(byteOffset, sizeof(byte) * count); if (IoResult.Success != check) { return check; } #if !DONT_CHECK_IO_BOUNDS if (buffer == null || offset < 0 || offset + count > buffer.Length) { return IoResult.AccessOutOfRange; } #endif fixed (byte *dst = &buffer[offset]) { Buffer.MoveMemory(dst, &data[byteOffset], count * sizeof(byte)); } return IoResult.Success; } [NoHeapAllocation] public unsafe IoResult Read16NoThrow(int byteOffset, [In, Out] ushort[] buffer, int offset, int count) { IoResult check = CheckRead(byteOffset, sizeof(ushort) * count); if (IoResult.Success != check) { return check; } #if !DONT_CHECK_IO_BOUNDS if (buffer == null || offset < 0 || offset + count > buffer.Length) { return IoResult.AccessOutOfRange; } #endif fixed (ushort *dst = &buffer[offset]) { Buffer.MoveMemory((byte *)dst, &data[byteOffset], count * sizeof(ushort)); } return IoResult.Success; } [NoHeapAllocation] public unsafe IoResult Read32NoThrow(int byteOffset, [In, Out] uint[] buffer, int offset, int count) { IoResult check = CheckRead(byteOffset, sizeof(uint) * count); if (IoResult.Success != check) { return check; } #if !DONT_CHECK_IO_BOUNDS if (buffer == null || offset < 0 || offset + count > buffer.Length) { return IoResult.AccessOutOfRange; } #endif fixed (uint *dst = &buffer[offset]) { Buffer.MoveMemory((byte *)dst, &data[byteOffset], count * sizeof(uint)); } return IoResult.Success; } [NoHeapAllocation] public unsafe IoResult Read64NoThrow(int byteOffset, [In, Out] ulong[] buffer, int offset, int count) { IoResult check = CheckRead(byteOffset, sizeof(ulong) * count); if (IoResult.Success != check) { return check; } #if !DONT_CHECK_IO_BOUNDS if (buffer == null || offset < 0 || offset + count > buffer.Length) { return IoResult.AccessOutOfRange; } #endif fixed (ulong *dst = &buffer[offset]) { Buffer.MoveMemory((byte *)dst, &data[byteOffset], count * sizeof(ulong)); } return IoResult.Success; } [NoHeapAllocation] public unsafe IoResult Write8NoThrow(int byteOffset, [In, Out] byte[] buffer, int offset, int count) { IoResult check = CheckWrite(byteOffset, sizeof(byte) * count); if (IoResult.Success != check) { return check; } #if !DONT_CHECK_IO_BOUNDS if (buffer == null || offset < 0 || offset + count > buffer.Length) { return IoResult.AccessOutOfRange; } #endif fixed (byte *src = &buffer[offset]) { Buffer.MoveMemory(&data[byteOffset], src, count * sizeof(byte)); } return IoResult.Success; } [NoHeapAllocation] public unsafe IoResult Write16NoThrow(int byteOffset, [In, Out] ushort[] buffer, int offset, int count) { IoResult check = CheckWrite(byteOffset, sizeof(ushort) * count); if (IoResult.Success != check) { return check; } #if !DONT_CHECK_IO_BOUNDS if (buffer == null || offset < 0 || offset + count > buffer.Length) { return IoResult.AccessOutOfRange; } #endif fixed (ushort *src = &buffer[offset]) { Buffer.MoveMemory(&data[byteOffset], (byte *)src, count * sizeof(ushort)); } return IoResult.Success; } [NoHeapAllocation] public unsafe IoResult Write32NoThrow(int byteOffset, [In, Out] uint[] buffer, int offset, int count) { IoResult check = CheckWrite(byteOffset, sizeof(uint) * count); if (IoResult.Success != check) { return check; } #if !DONT_CHECK_IO_BOUNDS if (buffer == null || offset < 0 || offset + count > buffer.Length) { return IoResult.AccessOutOfRange; } #endif fixed (uint *src = &buffer[offset]) { Buffer.MoveMemory(&data[byteOffset], (byte *)src, count * sizeof(uint)); } return IoResult.Success; } [NoHeapAllocation] public unsafe IoResult Write64NoThrow(int byteOffset, [In, Out] ulong[] buffer, int offset, int count) { IoResult check = CheckWrite(byteOffset, sizeof(ulong) * count); if (IoResult.Success != check) { return check; } #if !DONT_CHECK_IO_BOUNDS if (buffer == null || offset < 0 || offset + count > buffer.Length) { return IoResult.AccessOutOfRange; } #endif fixed (ulong *src = &buffer[offset]) { Buffer.MoveMemory(&data[byteOffset], (byte *)src, count * sizeof(ulong)); } return IoResult.Success; } // -------------------------------------------------------------------- [Inline] [NoHeapAllocation] public unsafe IoResult Write8NoThrow(int byteOffset, byte value) { IoResult check = CheckWrite(byteOffset, sizeof(byte)); if (IoResult.Success == check) { data[byteOffset] = value; } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Write16NoThrow(int byteOffset, ushort value) { IoResult check = CheckWrite(byteOffset, sizeof(ushort)); if (IoResult.Success == check) { *((ushort *)&data[byteOffset]) = value; } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Write32NoThrow(int byteOffset, uint value) { IoResult check = CheckWrite(byteOffset, sizeof(uint)); if (IoResult.Success == check) { *((uint *)&data[byteOffset]) = value; } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Write64NoThrow(int byteOffset, ulong value) { IoResult check = CheckWrite(byteOffset, sizeof(ulong)); if (IoResult.Success == check) { *((ulong *)&data[byteOffset]) = value; } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Write8NoThrow(int byteOffset, byte value, int count) { IoResult check = CheckWrite(byteOffset, sizeof(byte) * count); if (IoResult.Success == check) { byte *temp = &data[byteOffset]; while (count-- > 0) { *temp++ = value; } } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Write16NoThrow(int byteOffset, ushort value, int count) { IoResult check = CheckWrite(byteOffset, sizeof(ushort) * count); if (IoResult.Success == check) { ushort *temp = (ushort*) &data[byteOffset]; while (count-- > 0) { *temp++ = value; } } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Write32NoThrow(int byteOffset, uint value, int count) { IoResult check = CheckWrite(byteOffset, sizeof(uint) * count); if (IoResult.Success == check) { uint *temp = (uint*) &data[byteOffset]; while (count-- > 0) { *temp++ = value; } } return check; } [Inline] [NoHeapAllocation] public unsafe IoResult Write64NoThrow(int byteOffset, ulong value, int count) { IoResult check = CheckWrite(byteOffset, sizeof(ulong) * count); if (IoResult.Success == check) { ulong *temp = (ulong*) &data[byteOffset]; while (count-- > 0) { *temp++ = value; } } return check; } #endif // SINGULARITY_KERNEL #endregion // NoHeapAllocation Read/Write operations // -------------------------------------------------------------------- [Inline] [NoHeapAllocation] internal unsafe byte Read8Unchecked(int byteOffset) { return data[byteOffset]; } [Inline] [NoHeapAllocation] internal unsafe ushort Read16Unchecked(int byteOffset) { return *((ushort *)&data[byteOffset]); } [Inline] [NoHeapAllocation] internal unsafe uint Read32Unchecked(int byteOffset) { return *((uint *)&data[byteOffset]); } [Inline] [NoHeapAllocation] internal unsafe ulong Read64Unchecked(int byteOffset) { return *((ulong *)&data[byteOffset]); } public unsafe void Read8(int byteOffset, byte *values, int count) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + count * sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif Buffer.MoveMemory(values, &data[byteOffset], count * sizeof(byte)); } public unsafe void Read8(int byteOffset, [In, Out] byte[] buffer, int offset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + count * sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } if (buffer == null || offset < 0 || offset + count > buffer.Length) { Error.AccessOutOfRange(); } #endif fixed (byte *dst = &buffer[offset]) { Buffer.MoveMemory(dst, &data[byteOffset], count * sizeof(byte)); } } public unsafe void Read16(int byteOffset, [In, Out] ushort[] buffer, int offset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + count * sizeof(ushort) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } if (buffer == null || offset < 0 || offset + count > buffer.Length) { Error.AccessOutOfRange(); } #endif fixed (ushort *dst = &buffer[offset]) { Buffer.MoveMemory((byte *)dst, &data[byteOffset], count * sizeof(ushort)); } } public unsafe void Read32(int byteOffset, [In, Out] uint[] buffer, int offset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + count * sizeof(uint) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } if (buffer == null || offset < 0 || offset + count > buffer.Length) { Error.AccessOutOfRange(); } #endif fixed (uint *dst = &buffer[offset]) { Buffer.MoveMemory((byte *)dst, &data[byteOffset], count * sizeof(uint)); } } public unsafe void Read64(int byteOffset, [In, Out] ulong[] buffer, int offset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + count * sizeof(ulong) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } if (buffer == null || offset < 0 || offset + count > buffer.Length) { Error.AccessOutOfRange(); } #endif fixed (ulong *dst = &buffer[offset]) { Buffer.MoveMemory((byte *)dst, &data[byteOffset], count * sizeof(ulong)); } } public void Read8(int byteOffset, [In,Out] byte[] buffer) { Read8(byteOffset, buffer, 0, buffer.Length); } public void Read16(int byteOffset, [In,Out] ushort[] buffer) { Read16(byteOffset, buffer, 0, buffer.Length); } public void Read32(int byteOffset, [In,Out] uint[] buffer) { Read32(byteOffset, buffer, 0, buffer.Length); } public void Read64(int byteOffset, [In,Out] ulong[] buffer) { Read64(byteOffset, buffer, 0, buffer.Length); } public unsafe string ReadString(int byteOffset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!readable) { Error.ReadNotSupported(); } if (byteOffset + count * sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif char[] tempString = new char[count]; for(int i = 0; i < count; i++) { tempString[i] = (char)data[i + byteOffset]; } return new string(tempString); } public unsafe void WriteString(int byteOffset, string tempString) { int count = tempString.Length; #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif for(int i = 0; i < count; i++) { data[i + byteOffset] = (byte)tempString[i]; } } [Inline] public unsafe void Write8(int byteOffset, byte value) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif data[byteOffset] = value; } [Inline] public unsafe void Write16(int byteOffset, ushort value) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + sizeof(ushort) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif *((ushort *)&data[byteOffset]) = value; } [Inline] public unsafe void Write32(int byteOffset, uint value) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + sizeof(uint) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif *((uint *)&data[byteOffset]) = value; } [Inline] public unsafe void Write64(int byteOffset, ulong value) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + sizeof(ulong) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif *((ulong *)&data[byteOffset]) = value; } [Inline] [NoHeapAllocation] internal unsafe void Write8Unchecked(int byteOffset, byte value) { data[byteOffset] = value; } [Inline] [NoHeapAllocation] internal unsafe void Write16Unchecked(int byteOffset, ushort value) { *((ushort *)&data[byteOffset]) = value; } [Inline] [NoHeapAllocation] internal unsafe void Write32Unchecked(int byteOffset, uint value) { *((uint *)&data[byteOffset]) = value; } [Inline] [NoHeapAllocation] internal unsafe void Write64Unchecked(int byteOffset, ulong value) { *((ulong *)&data[byteOffset]) = value; } public unsafe void Write8(int byteOffset, byte value, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif byte *temp = &data[byteOffset]; while (count-- > 0) { *temp++ = value; } } public unsafe void Write16(int byteOffset, ushort value, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(ushort) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif ushort *temp = (ushort *)&data[byteOffset]; while (count-- > 0) { *temp++ = value; } } public unsafe void Write32(int byteOffset, uint value, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(uint) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif uint *temp = (uint *)&data[byteOffset]; while (count-- > 0) { *temp++ = value; } } public unsafe void Write64(int byteOffset, ulong value, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(ulong) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif ulong *temp = (ulong *)&data[byteOffset]; while (count-- > 0) { *temp++ = value; } } public unsafe void Write8(int byteOffset, byte[] values) { Write8(byteOffset, values, 0, values.Length); } public unsafe void Write16(int byteOffset, ushort[] values) { Write16(byteOffset, values, 0, values.Length); } public unsafe void Write32(int byteOffset, uint[] values) { Write32(byteOffset, values, 0, values.Length); } public unsafe void Write64(int byteOffset, ulong[] values) { Write64(byteOffset, values, 0, values.Length); } public unsafe void Write8(int byteOffset, byte *values, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } #endif Buffer.MoveMemory(&data[byteOffset], values, count * sizeof(byte)); } public unsafe void Write8(int byteOffset, byte[] buffer, int offset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(byte) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } if (buffer == null || offset < 0 || offset + count > buffer.Length) { Error.AccessOutOfRange(); } #endif fixed (byte *src = &buffer[offset]) { Buffer.MoveMemory(&data[byteOffset], src, count * sizeof(byte)); } } public unsafe void Write16(int byteOffset, ushort[] buffer, int offset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(ushort) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } if (buffer == null || offset < 0 || offset + count > buffer.Length) { Error.AccessOutOfRange(); } #endif fixed (ushort *src = &buffer[offset]) { Buffer.MoveMemory(&data[byteOffset], (byte *)src, count * sizeof(ushort)); } } public unsafe void Write32(int byteOffset, uint[] buffer, int offset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(uint) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } if (buffer == null || offset < 0 || offset + count > buffer.Length) { Error.AccessOutOfRange(); } #endif fixed (uint *src = &buffer[offset]) { Buffer.MoveMemory(&data[byteOffset], (byte *)src, count * sizeof(uint)); } } public unsafe void Write64(int byteOffset, ulong[] buffer, int offset, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (byteOffset + count * sizeof(ulong) > bytes || byteOffset < 0) { Error.AccessOutOfRange(); } if (buffer == null || offset < 0 || offset + count > buffer.Length) { Error.AccessOutOfRange(); } #endif fixed (ulong *src = &buffer[offset]) { Buffer.MoveMemory(&data[byteOffset], (byte *)src, count * sizeof(ulong)); } } public unsafe void Copy8(int byteSource, int byteDestination, int count) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { Error.WriteNotSupported(); } if (!readable) { Error.ReadNotSupported(); } if (byteDestination + count > bytes || byteDestination < 0) { Error.AccessOutOfRange(); } if (byteSource + count > bytes || byteSource < 0) { Error.AccessOutOfRange(); } #endif Buffer.MoveMemory(&data[byteDestination], &data[byteSource], count); } public unsafe void Copy16(int byteSource, int byteDestination, int count) { Copy8(byteSource, byteDestination, count * sizeof(ushort)); } public unsafe void Copy32(int byteSource, int byteDestination, int count) { Copy8(byteSource, byteDestination, count * sizeof(uint)); } public unsafe void Copy64(int byteSource, int byteDestination, int count) { Copy8(byteSource, byteDestination, count * sizeof(ulong)); } #if SINGULARITY_KERNEL [NoHeapAllocation] private IoResult CheckCopy(int byteSource, int byteDestination, int byteCount) { #if !DONT_CHECK_IO_BOUNDS if (!writable) { return IoResult.WriteNotSupported; } if (!readable) { return IoResult.ReadNotSupported; } if (byteDestination + byteCount > bytes || byteDestination < 0) { return IoResult.AccessOutOfRange; } if ((byteSource + byteCount) > bytes || byteSource < 0 || byteCount < 0) { return IoResult.AccessOutOfRange; } #endif // DONT_CHECK_IO_BOUNDS return IoResult.Success; } [NoHeapAllocation] public unsafe IoResult Copy8NoThrow(int byteSource, int byteDestination, int count) { int byteCount = count * sizeof(byte); IoResult check = CheckCopy(byteSource, byteDestination, byteCount); if (IoResult.Success == check) { Buffer.MoveMemory(&data[byteDestination], &data[byteSource], byteCount); } return check; } [NoHeapAllocation] public unsafe IoResult Copy16NoThrow(int byteSource, int byteDestination, int count) { return Copy8NoThrow(byteSource, byteDestination, count * sizeof(ushort)); } [NoHeapAllocation] public unsafe IoResult Copy32NoThrow(int byteSource, int byteDestination, int count) { return Copy8NoThrow(byteSource, byteDestination, count * sizeof(uint)); } [NoHeapAllocation] public unsafe IoResult Copy64NoThrow(int byteSource, int byteDestination, int count) { return Copy8NoThrow(byteSource, byteDestination, count * sizeof(ulong)); } #endif //SINGULARITY_KERNEL } }