singrdk/base/Kernel/Singularity/Io/IoMemory.cs

1603 lines
54 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// 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.
//
//| <include path='docs/doc[@for="ArrayList.this"]/*' />
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
}
}